In C or C++ (windows), how do you read RAM by giving a physical (not virtual) address? That means without going trough virtual memory system (mmu tables), and being specific
Under Windows you should use NativeAPI calls NtOpenSection and NtMapViewOfSection
Example from 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
is an analog of /dev/mem
under Linux, where you also have possibility to access physical memory directly. By the way, not sure about Windows, but under Linux only 1 Mb of physical address space is available, because it may contain some service low-level data like BIOS tables. Access to other physical memory may corrupt virtual memory, managed by the OS, and that's why it's not allowed
UPDATE: Provided code does not work under user-mode starting from Windows Vista. Instead you can call GetSystemFirmwareTable() to get useful information from 1st MB of raw memory without looking for it.
Bonus: reading physical memory under Linux (Debian 9) using Boost IO memory-mapped file, part of the class:
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);
}
Short Answer: No
Long Answer:
The C/C++ standard define a machine in very simple terms. There is no concept of virtual memory (just memory). These concepts are more the domain of the hardware and may be potentially accessed via the OS (if it is aware OS such things).
I would re-ask the question in terms of the facilities provided by your OS/Hardware.
You would have to write a kernel mode driver and use memory manager functions to map physical memory range to your kernel driver's system space then export functionality to a user API or driver.
After windows 98 it is not possible in most cases to access physical memory from user mode. As others have put it this is so any old program cant just destroy people's computers. You would have to write a kernel driver, which can only be installed if it is signed and first loaded into the window's store. This alone is not a simple process like linking a DLL.
In summary MmAllocateContiguousMemory()
is a windows kernel mode function which maps contiguous physical memory to system memory and is a part of ntoskrnl.exe
.
Also you can not call these API's from user mode applications. Only driver's can use them. User mode applications CANNOT access physical memory with out the help of a driver. The driver can either handle request's from the user API or use IOCTLs and map it's resources to the API's virtual memory. Either way you will need the help of a driver which has to be installed by plug n play manager. PnP has to choose to install the driver on it's own either by hardware activation i.e. hot plug or some other method like a bus driver that is always on.
Further windows randomly assign's virtual address so that it is not easily possible to discern any pattern or work out it's physical location.
I guess its not possible to access the physical address directly. Not even with administrative privilege.
Every address accessed by the the application is virtual address which is translated to physical address by hardware MMU.
One way is to configure MMU for one to one mapping the virtual address to physical address. This is usually done in embedded systems with no OS or before loading the OS.
With windows loaded. I believe your requirement is not possible.
Check this link: Access Physical Memory, Port and PCI Configuration Space
But start from Windows Vista, even WinHex cannot open the physical ram.
I would think a device driver must allow physical memory access, since devices such as PCI cards need to be accessed that way. If you can do it from a driver, then write a custom allocator for your "user" ( more like administrator ) mode program to easily link into C++.