Как вы читаете прямо из физической памяти?
В C или C++ (Windows), как вы читаете ОЗУ, давая физический (не виртуальный) адрес? Это означает, что не нужно проходить через систему виртуальной памяти (таблицы MMU) и быть специфичным для одного процесса.
Я уже знаю API ReadProcessMemory
, который читает из оперативной памяти (используется большинством тренеров), но это только для определенного процесса.
Я искал в MSDN и обнаружил, что Device\PhysicalMemory, по- видимому, предоставляет такую возможность, но я не нашел практического примера, и эта функция, похоже, была отключена пакетами обновления Windows (чтобы исправить некоторую уязвимость).
Я знаю, что это можно сделать, потому что это делает WinHex (если вы выбираете "tools" > "open ram" > "физической памяти"). Затем он отобразит содержимое оперативной памяти от 0x00000000 до your_ram_size, как при открытии традиционного файла. Это требует прав администратора, но нет драйвера для установки (что означает, что WinHex делает это из пользовательского режима).
РЕДАКТИРОВАТЬ: добавлена информация о ОС.
8 ответов
Вам придется написать драйвер режима ядра и использовать функции диспетчера памяти, чтобы отобразить диапазон физической памяти в системное пространство драйвера вашего ядра, а затем экспортировать функциональность в пользовательский API или драйвер.
После Windows 98 в большинстве случаев невозможно получить доступ к физической памяти из пользовательского режима. Как говорили другие, это так, что любая старая программа не может просто уничтожить компьютеры людей. Вам придется написать драйвер ядра, который можно установить, только если он подписан и сначала загружен в хранилище окна. Это само по себе не такой простой процесс, как связывание DLL.
В итоге MmAllocateContiguousMemory()
является функцией режима ядра Windows, которая отображает непрерывную физическую память в системную память и является частью ntoskrnl.exe
,
Также вы не можете вызывать эти API из приложений пользовательского режима. Их могут использовать только водители. Приложения пользовательского режима НЕ МОГУТ получить доступ к физической памяти без помощи драйвера. Драйвер может обрабатывать запросы от пользовательского API или использовать IOCTL и сопоставлять его ресурсы с виртуальной памятью API. В любом случае вам понадобится помощь драйвера, который должен быть установлен с помощью Plug N Play Manager. PnP должен выбрать установку драйвера самостоятельно либо с помощью аппаратной активации, то есть с помощью горячей замены, либо с помощью другого метода, такого как драйвер шины, который всегда включен.
Дальнейшие окна случайным образом назначают виртуальный адрес, так что не легко определить какой-либо шаблон или определить его физическое местоположение.
Ни язык C, ни C++ не определяют термин "память". Вещи определены в абстрактных терминах, таких как "хранение" и "классификаторы хранения". Указатели являются абстрактными вещами - их значения могут быть любыми, абсолютно не связанными с физическими или виртуальными адресами.
Только в контексте системы и ее реализации вводятся такие термины, как память и адресное пространство. А поскольку это специфичные для системы вещи, для доступа к ним необходимо использовать методы, предоставляемые ОС.
Даже при реализации ядра ОС вы должны получить доступ к вещам самого низкого уровня не через C (потому что это просто невозможно), а через методы, специфичные для реализации и архитектуры. Обычно это делается с помощью набора низкоуровневых функций, запрограммированных на ассемблере, которые написаны так, чтобы они соответствовали виду машинного кода, который генерирует компилятор. Это позволяет тем функциям, которые написаны на ассемблере, вызываться из C, как если бы они были скомпилированы компилятором.
Проверьте эту ссылку: Доступ к физической памяти, порту и конфигурации PCI
Но начните с Windows Vista, даже WinHex не может открыть физическую память.
Под Windows вы должны использовать вызовы NativeAPI NtOpenSection и NtMapViewOfSection
Пример от Марка Руссиновича
static BOOLEAN MapPhysicalMemory( HANDLE PhysicalMemory,
PDWORD Address, PDWORD Length,
PDWORD VirtualAddress )
{
NTSTATUS ntStatus;
PHYSICAL_ADDRESS viewBase;
char error[256];
*VirtualAddress = 0;
viewBase.QuadPart = (ULONGLONG) (*Address);
ntStatus = NtMapViewOfSection (PhysicalMemory,
(HANDLE) -1,
(PVOID) VirtualAddress,
0L,
*Length,
&viewBase,
Length,
ViewShare,
0,
PAGE_READONLY );
if( !NT_SUCCESS( ntStatus )) {
sprintf_s( error, "Could not map view of %X length %X",
*Address, *Length );
PrintError( error, ntStatus );
return FALSE;
}
*Address = viewBase.LowPart;
return TRUE;
}
static HANDLE OpenPhysicalMemory()
{
NTSTATUS status;
HANDLE physmem;
UNICODE_STRING physmemString;
OBJECT_ATTRIBUTES attributes;
WCHAR physmemName[] = L"\\device\\physicalmemory";
RtlInitUnicodeString( &physmemString, physmemName );
InitializeObjectAttributes( &attributes, &physmemString,
OBJ_CASE_INSENSITIVE, NULL, NULL );
status = NtOpenSection( &physmem, SECTION_MAP_READ, &attributes );
if( !NT_SUCCESS( status )) {
PrintError( "Could not open \\device\\physicalmemory", status );
return NULL;
}
return physmem;
}
\device\physicalmemory
является аналогом /dev/mem
под Linux, где у вас также есть возможность прямого доступа к физической памяти. Кстати, не уверен насчет Windows, но под Linux доступно только 1 МБ физического адресного пространства, поскольку оно может содержать некоторые служебные низкоуровневые данные, такие как таблицы BIOS. Доступ к другой физической памяти может привести к повреждению виртуальной памяти, управляемой ОС, и поэтому не допускается
ОБНОВЛЕНИЕ: предоставленный код не работает в пользовательском режиме, начиная с Windows Vista. Вместо этого вы можете вызвать GetSystemFirmwareTable(), чтобы получить полезную информацию из 1-го МБ сырой памяти, не ища ее.
Бонус: чтение физической памяти под Linux (Debian 9) с использованием файла сопоставления памяти Boost IO, часть класса:
NativePhysicalMemory::NativePhysicalMemory(size_t base, size_t length)
: physical_memory_map_(std::make_unique<boost::iostreams::mapped_file_source>())
{
map_physical_memory(base, length);
}
// ...
void NativePhysicalMemory::map_physical_memory(size_t base, size_t length)
{
#ifdef _SC_PAGESIZE
size_t mempry_page_offset = base % sysconf(_SC_PAGESIZE);
#else
size_t mempry_page_offset = base % getpagesize();
#endif /* _SC_PAGESIZE */
boost_io::mapped_file_params params = {};
params.path = "/dev/mem";
params.flags = boost_io::mapped_file::mapmode::readonly;
params.length = length + mempry_page_offset;
params.offset = base - mempry_page_offset;
params.hint = nullptr;
physical_memory_map_->open(params);
}
Я бы подумал, что драйвер устройства должен разрешать физический доступ к памяти, поскольку к таким устройствам, как карты PCI, нужно обращаться таким образом. Если вы можете сделать это из драйвера, то напишите специальный распределитель для вашей программы в режиме "пользователь" (более похожий на администратора), чтобы легко ссылаться на C++.
Расширяя ответ корабля, вместо того, чтобы писать свой собственный драйвер и платить Microsoft за его подпись, вы можете загрузить существующий подписанный драйвер, который предоставляет необходимые ioctl. Они довольно распространены, KDU перечисляет несколько. Это уже было сделано в kdmapper с помощью включенного большого двоичного объекта сетевого драйвера Intel. Проект предоставляет функции пользовательского режима для поиска адресов virt->phy, сопоставления и т. д. вintel_driver::*
предназначен для ручного сопоставления неподписанных драйверов ядра.
Я думаю, что Microsoft удаляет пользовательский режим\Device\PhysicalMemory
было большой ошибкой. Конечно, доступ к физической памяти может быть опасен, но Linux явно считает, что ограничение доступа для администраторов — это нормально, учитывая/dev/mem
существует именно так, как он работал на окнах. Многим низкоуровневым пользовательским приложениям он нужен для повышения производительности, поэтому это такой распространенный эксплойт драйвера.
Я предполагаю, что невозможно получить доступ к физическому адресу напрямую. Даже с административными привилегиями.
Каждый адрес, к которому обращается приложение, является виртуальным адресом, который преобразуется в физический адрес аппаратным MMU.
Одним из способов является настройка MMU для сопоставления виртуального адреса с физическим адресом. Обычно это делается во встроенных системах без ОС или перед загрузкой ОС.
С загруженными окнами. Я считаю, что ваше требование не возможно.
Краткий ответ: нет
Длинный ответ:
Стандарт C/C++ определяет машину в очень простых терминах. Нет понятия виртуальной памяти (просто память). Эти понятия больше относятся к области аппаратного обеспечения и могут быть потенциально доступны через ОС (если она знает об ОС такие вещи).
Я хотел бы повторно задать вопрос с точки зрения возможностей, предоставляемых вашей ОС / аппаратным обеспечением.