/* XMRig * Copyright (c) 2018-2021 SChernykh * Copyright (c) 2016-2021 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "hw/msr/Msr.h" #include "backend/cpu/Cpu.h" #include "base/io/log/Log.h" #include "base/kernel/Platform.h" #include #include #include #include #define SERVICE_NAME L"WinRing0_1_2_0" #define IOCTL_READ_MSR CTL_CODE(40000, 0x821, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_WRITE_MSR CTL_CODE(40000, 0x822, METHOD_BUFFERED, FILE_ANY_ACCESS) namespace xmrig { static const wchar_t *kServiceName = SERVICE_NAME; class MsrPrivate { public: bool uninstall() { if (driver != INVALID_HANDLE_VALUE) { CloseHandle(driver); } if (!service) { return true; } bool result = true; if (!reuse) { SERVICE_STATUS serviceStatus; if (!ControlService(service, SERVICE_CONTROL_STOP, &serviceStatus)) { result = false; } if (!DeleteService(service)) { LOG_ERR("%s " RED("failed to remove WinRing0 driver, error %u"), Msr::tag(), GetLastError()); result = false; } } CloseServiceHandle(service); service = nullptr; return result; } bool reuse = false; HANDLE driver = INVALID_HANDLE_VALUE; SC_HANDLE manager = nullptr; SC_HANDLE service = nullptr; }; } // namespace xmrig xmrig::Msr::Msr() : d_ptr(new MsrPrivate()) { DWORD err = 0; d_ptr->manager = OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS); if (!d_ptr->manager) { if ((err = GetLastError()) == ERROR_ACCESS_DENIED) { LOG_WARN("%s " YELLOW_BOLD("to access MSR registers Administrator privileges required."), tag()); } else { LOG_ERR("%s " RED("failed to open service control manager, error %u"), tag(), err); } return; } std::vector dir; do { dir.resize(dir.empty() ? MAX_PATH : dir.size() * 2); GetModuleFileNameW(nullptr, dir.data(), dir.size()); err = GetLastError(); } while (err == ERROR_INSUFFICIENT_BUFFER); if (err != ERROR_SUCCESS) { LOG_ERR("%s " RED("failed to get path to driver, error %u"), tag(), err); return; } for (auto it = dir.end() - 1; it != dir.begin(); --it) { if ((*it == L'\\') || (*it == L'/')) { ++it; *it = L'\0'; break; } } const std::wstring path = std::wstring(dir.data()) + L"WinRing0x64.sys"; d_ptr->service = OpenServiceW(d_ptr->manager, kServiceName, SERVICE_ALL_ACCESS); if (d_ptr->service) { LOG_WARN("%s " YELLOW("service ") YELLOW_BOLD("WinRing0_1_2_0") YELLOW(" already exists"), tag()); SERVICE_STATUS status; const auto rc = QueryServiceStatus(d_ptr->service, &status); if (rc) { DWORD dwBytesNeeded = 0; QueryServiceConfigA(d_ptr->service, nullptr, 0, &dwBytesNeeded); if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { std::vector buffer(dwBytesNeeded); auto config = reinterpret_cast(buffer.data()); if (QueryServiceConfigA(d_ptr->service, config, buffer.size(), &dwBytesNeeded)) { LOG_INFO("%s " YELLOW("service path: ") YELLOW_BOLD("\"%s\""), tag(), config->lpBinaryPathName); } } } if (rc && status.dwCurrentState == SERVICE_RUNNING) { d_ptr->reuse = true; } else if (!d_ptr->uninstall()) { return; } } if (!d_ptr->reuse) { d_ptr->service = CreateServiceW(d_ptr->manager, kServiceName, kServiceName, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, path.c_str(), nullptr, nullptr, nullptr, nullptr, nullptr); if (!d_ptr->service) { LOG_ERR("%s " RED("failed to install WinRing0 driver, error %u"), tag(), GetLastError()); return; } if (!StartService(d_ptr->service, 0, nullptr)) { err = GetLastError(); if (err != ERROR_SERVICE_ALREADY_RUNNING) { if (err == ERROR_FILE_NOT_FOUND) { LOG_ERR("%s " RED("failed to start WinRing0 driver: ") RED_BOLD("\"WinRing0x64.sys not found\""), tag()); } else { LOG_ERR("%s " RED("failed to start WinRing0 driver, error %u"), tag(), err); } d_ptr->uninstall(); return; } } } d_ptr->driver = CreateFileW(L"\\\\.\\" SERVICE_NAME, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (d_ptr->driver == INVALID_HANDLE_VALUE) { LOG_ERR("%s " RED("failed to connect to WinRing0 driver, error %u"), tag(), GetLastError());; } } xmrig::Msr::~Msr() { d_ptr->uninstall(); delete d_ptr; } bool xmrig::Msr::isAvailable() const { return d_ptr->driver != INVALID_HANDLE_VALUE; } bool xmrig::Msr::write(Callback &&callback) { const auto &units = Cpu::info()->units(); bool success = false; std::thread thread([&callback, &units, &success]() { for (int32_t pu : units) { if (!Platform::setThreadAffinity(pu)) { continue; } if (!callback(pu)) { return; } } success = true; }); thread.join(); return success; } bool xmrig::Msr::rdmsr(uint32_t reg, int32_t cpu, uint64_t &value) const { assert(cpu < 0); DWORD size = 0; return DeviceIoControl(d_ptr->driver, IOCTL_READ_MSR, ®, sizeof(reg), &value, sizeof(value), &size, nullptr) != 0; } bool xmrig::Msr::wrmsr(uint32_t reg, uint64_t value, int32_t cpu) { assert(cpu < 0); struct { uint32_t reg = 0; uint32_t value[2]{}; } input; static_assert(sizeof(input) == 12, "Invalid struct size for WinRing0 driver"); input.reg = reg; *(reinterpret_cast(input.value)) = value; DWORD output; DWORD k; return DeviceIoControl(d_ptr->driver, IOCTL_WRITE_MSR, &input, sizeof(input), &output, sizeof(output), &k, nullptr) != 0; }