Пожалуйста, обратите внимание, что пользователь заблокирован
Введение
В этой статье я хотел бы рассмотреть один из способов получения информации об операционной системе через ключи реестра Windows в пользовательском режиме (ring 3), однако, аналогичным образом могут быть получены данные и в режиме ядра (ring 0).Известно, что поля MajorVersion, MinorVersion и BuildNumber могут быть извлечены напрямую из структуры _PEB или через вызов RtlGetVersion в режиме ядра, которая, в свою очередь, возвращает указатель на структуру _OSVERSIONINFO. Эта информация может быть использована при разработке эксплойтов или какого-либо легитимного ПО. Особенно справедливо это для версий Windows 10, Windows Server 2016/2019, которые имеют дополнительное поле UBR (Update Build Revision), не представленное структурой _PEB. Например, если вы разрабатываете эксплойт для CVE-2020-17087, то из двух версий ОС 19042.542 и 19042.630 уязвимой будет только первая. Следовательно, проверки по BuildNumber недостаточно и желательно дополнительно проверять поле UBR. Это будет надежнее, т. к., отпадает вероятность попытки эксплуатации пропатченного билда. Безусловно, есть и другие способы, основанные на проверке версии файлов, но в этой статье мы их не будем рассматривать.
Ключи реестра
Для наших целей может подойти два ключа:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion и
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion.
Оба ключа идентичны с той лишь разницей, что второй используется как редиректор на 64-битных системах. Например, когда 32-битное приложение читает значение ключа из HKEY_LOCAL_MACHINE\SOFTWARE\<компания>\<продукт>, то оно в действительности его получает из HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\<компания>\<продукт>.
В качестве тестируемых значений мы попробуем получить данные полей CurrentMajorVersionNumber, CurrentMinorVersionNumber, CurrentBuild и UBR.
Функции RegOpenKeyEx и RegQueryValueEx
В качестве кандидатов для выполнения нашей задачи нам потребуются Windows API RegOpenKeyEx и RegQueryValueEx.Прототип функций выглядит следующим образом:
Код:
LSTATUS RegOpenKeyExA(
HKEY hKey,
LPCSTR lpSubKey,
DWORD ulOptions,
REGSAM samDesired,
PHKEY phkResult
);
LSTATUS RegQueryValueExA(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
Сам код довольно примитивный и не требует дополнительных разъяснений.
C:
#include <windows.h>
#include <winreg.h>
#include <stdio.h>
extern "C"
int ShowWindVer()
{
// Объявлям переменные типа DWORD, которые будут хранить необходимые значения.
// Поскольку запись реестра CurrentBuild имеет тип REG_SZ, то
// результат мы сохраняем в массив
DWORD mj_ver, min_ver, ubr, dwType, size;
BYTE cur_build[256];
HKEY hKey;
LSTATUS retValue;
LPCSTR lpSubkey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
// Открываем хэндл ключа для чтения
retValue = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
lpSubkey,
NULL,
KEY_QUERY_VALUE,
&hKey);
// Проверяем возвращаемое значение
if (ERROR_SUCCESS != retValue) {
printf("RegOpenKeyEx err=%ld\n", retValue);
return 1;
}
// Получаем значение CurrentMajorVersionNumber
size = sizeof(DWORD);
retValue = RegQueryValueExA(hKey,
"CurrentMajorVersionNumber",
NULL,
&dwType,
(LPBYTE)&mj_ver,
&size);
if (ERROR_SUCCESS != retValue) {
printf("MajorVersion err=%ld\n", retValue);
return 1;
}
// Получаем значение CurrentMinorVersionNumber
size = sizeof(DWORD);
retValue = RegQueryValueExA(hKey,
"CurrentMinorVersionNumber",
NULL,
&dwType,
(LPBYTE)&min_ver,
&size);
if(ERROR_SUCCESS != retValue) {
printf("MinorVersion err=%ld\n", retValue);
return 1;
}
// Получаем значение CurrentBuild
memset(cur_build, 0, sizeof(cur_build));
size = sizeof(cur_build);
retValue = RegQueryValueExA(hKey,
"CurrentBuild",
NULL,
&dwType,
(LPBYTE)&cur_build,
&size);
if (ERROR_SUCCESS != retValue) {
printf("CurrentBuild err=%ld", retValue);
return 1;
// Обрабатываем ERROR_MORE_DATA при необходимости
// ...
}
// Получаем значение UBR
size = sizeof(DWORD);
retValue = RegQueryValueExA(hKey,
"UBR",
NULL,
&dwType,
(LPBYTE)&ubr,
&size);
if (ERROR_SUCCESS != retValue) {
printf("UBR err=%ld", retValue);
return 1;
}
// Выводим результат
printf("The Windows version is: %d.%d.%s.%d\n",
mj_ver,
min_ver,
cur_build,
ubr);
size = 0;
memset(cur_build, 0, sizeof(cur_build));
RegCloseKey(hKey);
return 0;
}
extern "C"
int main()
{
ShowWindVer();
}
Любые замечания, идеи и вопросы прошу оставлять в комментариях.
Последнее редактирование: