28

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 to one process.

I already know the API ReadProcessMemory, which reads from ram (used by most trainers) but it is only for a specific process.

I searched on MSDN and found that Device\PhysicalMemory seems to give such possibility, but I found no practical example and this feature seems to have been turned off by Windows service packs (to fix some vulnerability).

I know it is possible to do because WinHex does it (if you choose "tools" > "open ram" > "physical memory"). It will then display RAM content from 0x00000000 to your_ram_size just like when you open a traditional file. It requires administrator rights, but there is no driver to install (which means WinHex does it from user mode).

EDIT : added information about os.

9
  • 2
    try "link -dump -imports" on WinHex and see what functions it calls. Commented Dec 6, 2011 at 16:53
  • 1
    @Alexandre C. : I'd like to write a trainer for a game. I never know in advance where (which process) the values will be so i thought it will be easier to scan everything (winhex does it very quickly). I can already do it manually (using winhex), but it will be better to have some automatic program doing it.
    – tigrou
    Commented Dec 6, 2011 at 17:00
  • 8
    The physical memory mapping is rather unstable, and contains far more memory than the game process. So, it seems a step backwards from ReadProcessMemory.
    – MSalters
    Commented Dec 6, 2011 at 17:04
  • 4
    If you're writing a cheat program for a game, then you at least know that the value you want will be in that process's memory. Furthermore, that process's memory won't necessarily be in physical RAM at the time you look for it, so ReadProcessMemory really is the ideal function for your needs. It will read from the page file, and it will let you use stable addresses. Commented Dec 6, 2011 at 17:04
  • 3
    For your trainer, you'll want to do offsets from a base VA anyway, as the image in memory of the executable will change from execution to execution. So, you'll do better to determine the location of the variable of interest, calculate the offset, and use that to get a process VA.
    – tdenniston
    Commented Dec 6, 2011 at 17:04

7 Answers 7

10

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 can't 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 drivers can use them. User mode applications CANNOT access physical memory without the help of a driver. The driver can either handle reques's from the user API or use IOCTLs and map its resources to the user program virtual memory. Either way you will need the help of a driver which has to be installed by the plug n play manager. PnP has to choose to install the driver on its 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.

5
  • DOLLx8KD is a dll you can use to access ram till windows 7 (actually its a kernal mode driver ^ with a user mode driver, you can call it's fucntion through the dll. in c) Commented Jan 9, 2015 at 3:45
  • Another common use would be direct memory access or DMA. In which case the independent hardware accesses phsysical memory directly without going through the processor or memory manager. Commented May 9, 2015 at 6:33
  • Also it looks like ReadProcessMemory() is just a method that allows inter-process communication via memory. it would still be a virtual memory address. Commented May 9, 2015 at 6:43
  • The second link appears to be type's made by microsoft which manage physical memory and designed to be used in some setting. It is not a method to actually acquire those objects. Commented May 9, 2015 at 6:50
  • not sure about winHex, have you seen the source? how do you know it doesnt call a driver? Commented May 9, 2015 at 6:58
8

Neither the language C, nor C++ defines the term "memory". Things are defined in abstract terms like "storage" and "storage classifiers". Pointers are abstract things -- their values can be anything, totally unrelated to the physical or virtual addresses.

Only in the context of a system and its implementation are terms like memory and address space introduced. And since those are system specific things, one must use the methods provided by the OS to access them.

Even when implementing an OS kernel you have to do access to lowest level stuff not through C (because it simply can't), but through methods specific to implementation and architecture. Usually this is done through a set of low level functions programmed in assembly, which are written in a way that they match the kind of machine code the compiler generates. This allows those functions written in assembly to be called from C as if they were compiled by the compiler.

25
  • daten is this correct? The only thing you can't do with C is access the instruction pointer. Once you set that up and tell the CPU where to start executing from, you can basically start executing compiled code. Now you mightn't want to do it without a decent, competent API but you can easily point directly into physical memory via compiled code if you wish as much as you could using assembly - for modern machines this is all MMU dependent of course anyways. But on lesser machines or older machines you can access physical memory via compiled code.
    – cdcdcd
    Commented Jan 9, 2017 at 22:08
  • @cdcdcd: Yes, compiled code, which is architecture binary can of course access memory. But the C programming language (and C++, too) do not have a mechanism built in to directly access arbitrary memory locations. A pointer must always be taken by either applying the address-of operator (&) on a valid C storage object. Or the implementation may provide implementation dependent access to arbitrary memory locations. For example in the Linux kernel, for each architecture there's an implementation for memory access, e.g. for x86: lxr.free-electrons.com/source/arch/x86/include/asm/io.h
    – datenwolf
    Commented Jan 9, 2017 at 23:30
  • @cdcdcd: Just to be clear, that Linux kernel source code uses inline assembly to define C function interfaces, which function bodies are not written in C, but written directly in machine language, because C does not have a language defined mechanism for memory access.
    – datenwolf
    Commented Jan 9, 2017 at 23:31
  • 1
    Are you sure about this? Can you provide a reference. Whether physical memory is can be accessed directly has nothing to do with the language. You're argument is one of mindset. You could just as easily write a compiler to produce the same machine code from .c, as the hand crafted machine code you're referring to. Given your logic one could argue that assembly cannot access memory address because it requires an assembler. Of course in both C and assembly's case the source code does not directly address memory (until compiled and loaded) but then neither does the machine code until executed.
    – cdcdcd
    Commented Jan 10, 2017 at 0:00
  • 1
    Just because you can doesn't mean that you should. Given that, some systems allow you to, and you can read a byte's worth at 0x00 - there is no undefined behavior here, the order of events is predictable and for a system where this is permissible, and is targeted by a compiler; it will deal with it correctly (read and write the content to v). A compiler for a modern platform may throw a warning. Remember many systems have custom made compilers. Again, you could write assembly to do essentially the same thing. If you're worried about optimisation just use volatile.
    – cdcdcd
    Commented Jan 10, 2017 at 16:37
5

Check this link: Access Physical Memory, Port and PCI Configuration Space

But start from Windows Vista, even WinHex cannot open the physical ram.

1
  • 1
    This does require writing a driver though. The OP claims WinHex is able to do this without a driver -- I'm quite sceptical about this, though.
    – Martin B
    Commented Dec 6, 2011 at 17:20
4

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);
}
3
  • Works perfectly under Administrator privileges, and root respectively
    – user707779
    Commented Dec 19, 2017 at 15:45
  • 2
    Yeah, sorry, my fault - it really does not work under user-mode starting from Windows 7 (works on old systems like XP). In replace you can read SMBIOS tables using WinAPI call. Though, under Linux reading from /dev/mem is still possible :)
    – user707779
    Commented Dec 21, 2017 at 1:01
  • 1
    Once again, does not starting from Windows 7, from Vista of course (something with my memory, I don't mean RAM =)) Updated the answer.
    – user707779
    Commented Dec 21, 2017 at 3:29
2

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++.

1
  • 2
    PCI drivers use DMA circuits for data transferso the CPU (you use to code) is not involved. So for all practical purposes, this shouldn't help. Commented Dec 6, 2011 at 17:39
0

Expanding on craft's answer, instead of writing your own driver and paying Microsoft to sign it, you could load an existing signed driver that exposes the required ioctls. They are quite common, KDU lists a few. This has already been done in kdmapper using an included intel network driver blob. The project exposes user-mode functions for virt->phy address lookup, mapping, etc. in intel_driver::* intended for manual mapping unsigned kernel drivers.

I think Microsoft removing user-mode \Device\PhysicalMemory was a big mistake. Sure physical memory access can be dangerous, but clearly linux thinks restricting access to administrators is fine considering /dev/mem exists which is exactly how it used to work on windows. A lot of low-level user-apps need it for performance which is why this is such a common driver exploit.

-1

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.

1
  • 1
    It's possible both from POSIX - /dev/mem and from Windows NtOpenSection(L"\\Device\\PhysicalMemory")
    – user707779
    Commented Jan 12, 2017 at 10:52

Not the answer you're looking for? Browse other questions tagged or ask your own question.