c++ - ¿Cómo se lee directamente desde la memoria física?
windows memory (7)
Creo que un controlador de dispositivo debe permitir el acceso a la memoria física, ya que se necesita acceder a dispositivos como tarjetas PCI de esa manera. Si puede hacerlo desde un controlador, escriba un asignador personalizado para su programa de modo "usuario" (más como administrador) para vincularlo fácilmente a C ++.
En C o C ++ (Windows), ¿cómo se lee la RAM dando una dirección física (no virtual)? Eso significa sin pasar por el sistema de memoria virtual (tablas mmu) y ser específico para un proceso.
Ya conozco el API ReadProcessMemory
, que se lee de ram (utilizado por la mayoría de los entrenadores) pero es solo para un proceso específico.
Busqué en MSDN y encontré que Device/PhysicalMemory parece dar tal posibilidad, pero no encontré ningún ejemplo práctico y esta característica parece haber sido desactivada por los paquetes de servicio de Windows (para corregir alguna vulnerabilidad).
Sé que es posible hacerlo porque WinHex lo hace (si eliges "herramientas"> "abrir ram"> "memoria física"). A continuación, mostrará el contenido de RAM de 0x00000000 a your_ram_size, al igual que cuando abre un archivo tradicional. Requiere derechos de administrador, pero no hay ningún controlador para instalar (lo que significa que WinHex lo hace desde el modo de usuario).
EDITAR: información agregada sobre os.
En Windows debe usar las llamadas NtOpenSection y NtMapViewOfSection
Ejemplo de Mark Russinovich
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
es un análogo de /dev/mem
en Linux, donde también tienes la posibilidad de acceder directamente a la memoria física. Por cierto, no estoy seguro acerca de Windows, pero en Linux solo está disponible 1 Mb de espacio de direcciones físicas, ya que puede contener algunos datos de bajo nivel de servicio, como tablas de BIOS. El acceso a otra memoria física puede dañar la memoria virtual, administrada por el sistema operativo, y es por eso que no está permitido
ACTUALIZACIÓN: el código provisto no funciona en modo usuario a partir de Windows Vista. En su lugar, puede llamar a GetSystemFirmwareTable () para obtener información útil del 1er MB de memoria sin procesar sin buscarla.
Bonificación: leer la memoria física en Linux (Debian 9) usando el archivo mapeado de memoria Boost IO, parte de la clase:
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);
}
Ni el lenguaje C ni el C ++ definen el término "memoria". Las cosas se definen en términos abstractos, como "almacenamiento" y "clasificadores de almacenamiento". Los punteros son cosas abstractas; sus valores pueden ser cualquier cosa, sin relación alguna con las direcciones físicas o virtuales.
Solo en el contexto de un sistema y su implementación se introducen términos como memoria y espacio de direcciones. Y dado que esas son cosas específicas del sistema, uno debe usar los métodos proporcionados por el sistema operativo para acceder a ellos.
Incluso cuando se implementa un kernel de sistema operativo, debe tener acceso al material de nivel más bajo, no a través de C (porque simplemente no puede), sino a través de métodos específicos para la implementación y la arquitectura. Por lo general, esto se realiza a través de un conjunto de funciones de bajo nivel programadas en ensamblaje, que se escriben de manera que coincidan con el tipo de código de máquina que genera el compilador. Esto permite que las funciones escritas en ensamble sean llamadas desde C como si fueran compiladas por el compilador.
Respuesta corta: no
Respuesta larga:
El estándar C / C ++ define una máquina en términos muy simples. No hay concepto de memoria virtual (solo memoria). Estos conceptos son más del dominio del hardware y se puede acceder potencialmente a través del sistema operativo (si es consciente del sistema operativo tales cosas).
Volvería a hacer la pregunta en términos de las facilidades proporcionadas por su SO / Hardware.
Supongo que no es posible acceder directamente a la dirección física. Ni siquiera con privilegio administrativo.
Cada dirección a la que accede la aplicación es una dirección virtual que se traduce a la dirección física por hardware MMU.
Una forma es configurar MMU para mapear uno a uno la dirección virtual a la dirección física. Esto generalmente se realiza en sistemas integrados sin SO o antes de cargar el sistema operativo.
Con ventanas cargadas Creo que su requisito no es posible.
Tendría que escribir un controlador de modo kernel y utilizar las funciones del administrador de memoria para asignar el rango de la memoria física al espacio del sistema del controlador del kernel y luego exportar la funcionalidad a una API o controlador de usuario.
Después de Windows 98, en la mayoría de los casos, no es posible acceder a la memoria física desde el modo de usuario. Como otros lo han expresado, esto significa que cualquier programa antiguo no puede destruir las computadoras de las personas. Tendría que escribir un controlador de núcleo, que solo puede instalarse si está firmado y se lo cargó primero en la tienda de la ventana. Esto solo no es un proceso simple como vincular una DLL.
En resumen, MmAllocateContiguousMemory()
es una función de modo kernel de Windows que mapea la memoria física contigua a la memoria del sistema y es parte de ntoskrnl.exe
.
Tampoco puedes llamar a estas API desde aplicaciones en modo usuario. Solo el conductor puede usarlos. Las aplicaciones del modo de usuario NO PUEDEN acceder a la memoria física sin la ayuda de un controlador. El controlador puede manejar las solicitudes desde la API del usuario o usar IOCTLs y asignar sus recursos a la memoria virtual de la API. De cualquier manera, necesitará la ayuda de un controlador que debe ser instalado por Plug n Play Manager. PnP tiene que optar por instalar el controlador por sí solo, ya sea por activación de hardware, es decir, conexión en caliente o algún otro método, como un controlador de bus que está siempre encendido.
Otras ventanas asignan aleatoriamente la dirección virtual para que no sea fácil discernir ningún patrón o resolver su ubicación física.
Verifique este enlace: Acceso a memoria física, puerto y espacio de configuración PCI
Pero comience desde Windows Vista, incluso WinHex no puede abrir el ram físico.