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.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
tigrou
  • 4,236
  • 5
  • 33
  • 59
  • 2
    try "link -dump -imports" on WinHex and see what functions it calls. – John Knoeller Dec 06 '11 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 Dec 06 '11 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 Dec 06 '11 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. – Rob Kennedy Dec 06 '11 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 Dec 06 '11 at 17:04
  • To the OP: You'll probably want to use a combination of `CreateRemoteThread(Ex)` and `LoadLibrary`. All this physical memory stuff is nonsense and highly unnecessary. – Seth Carnegie Dec 06 '11 at 17:11
  • Are you sure WinHex doesn't use a driver to do this? This just doesn't seem like something that should be possible from user mode, even with administrative privileges... – Martin B Dec 06 '11 at 17:21
  • Although quite old, this http://www.codeproject.com/KB/system/soviet_kernel_hack.aspx might at least be interessing to try out ;-) – alk Dec 06 '11 at 17:37
  • ... or which means WinHex uses a KM driver to achieve it. – 0xC0000022L Mar 29 '16 at 19:41

8 Answers8

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.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
marshal craft
  • 439
  • 5
  • 18
  • 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) – marshal craft Jan 09 '15 at 03: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. – marshal craft May 09 '15 at 06: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. – marshal craft May 09 '15 at 06: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. – marshal craft May 09 '15 at 06:50
  • not sure about winHex, have you seen the source? how do you know it doesnt call a driver? – marshal craft May 09 '15 at 06: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.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • 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 Jan 09 '17 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 Jan 09 '17 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 Jan 09 '17 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 Jan 10 '17 at 00:00
  • ....daten I add here that modern systems use MMU. As Linux does but the kernel has logical address space that maps directly to physical memory and can be used for DMA (this is, as far as I'm aware was written in C). However, single, flat memory space systems still exist and C is used to access physical memory directly (see embedded systems). Historically, many DOS games were written in C as they allowed direct VGA memory access to essentially "accelerate" the rendering (see DOOM on github). – cdcdcd Jan 10 '17 at 00:36
  • @cdcdcd: This has **absolutely nothing** to do with the availability of MMU or virtual memory or DMA all that jazz. The C programming language is completely agnostic about memory on the hardware level. Of course C knows about memory in a very abstract sense. But C calls it "storage objects" and you can either allocate storage from automatic memory (which would be the stack on usual systems) or from dynamic memory (called the heap on usual systems). But there's no way in **pure** C to say "hey, I want to access the memory region from address, say, 0x00001000 to 0x01000000". – datenwolf Jan 10 '17 at 08:33
  • @cdcdcd: If you want to access memory at a specific address (be it virtual, physical or in an I/O region) you need some helper method, which deep down can not be written in C, but assembly, and will give you a pointer that adheres to the C semantics of memory. **C is not a high level assembler!** Some C implementations allow you to cast integers to pointers to be interpreted as addresses in the programs address space (virtually every C implementation for microcontrollers), but for something running in virtual address space don't rely on that. – datenwolf Jan 10 '17 at 08:37
  • @cdcdcd: To summarize: The **C language standard** does not define any method to absolutely address memory of the machine the program is going to run on. Behind the scenes the compiler, of course, is translating everything into accesses to raw memory addresses. And at the linking stage you can usually force the linker (using a linker script) to place certain symbols at specific address locations; for example you could force the linker to place the symbol `int foo;` at address 0x0010; but if you later on wrote `int *p = 0x0010;` there's no reason to expect it to actually point to `foo`. – datenwolf Jan 10 '17 at 08:42
  • @cdcdcd: **But** it is perfectly possible to declare a function `void *at_addr(long address);` which internally is implemented with assembly, and if you used that function like this `int *q = at_addr(0x0010);` then it actually will point to that location, because the innards of `at_addr` can be written in a way to match whatever you forced the linker to do with the linker script. But all of this is outside the scope of the *C programming language __specification__* and thus we can say, that it is impossible to do using just C. – datenwolf Jan 10 '17 at 08:46
  • @cdcdcd: And just for completeness, the way you'd directly access physical memory in *nix like OSs would be as follows: First you do `int fd_mem = open("/dev/mem", O_RDWR);` and then you can `void *ptr = mmap(0, size, PROT_READ|PROT_WRITE, 0, fd_mem, address);`, then `ptr` will point to physical memory starting at `address` up to `address+size`. But deep down inside the OS kernel the implementation of `mmap` on `/dev/mem` boils down to some lower than C level manipulation of CPU registers. – datenwolf Jan 10 '17 at 09:12
  • danten if you were correct then most simple 8/16bit embedded mircosystem code would fail and planes would start falling out of the sky. So for a 16bit system with single, flat memory address space (physical memory - there is no virtual memory, only DMA), using static int16* ptr = 0x100 you can write and read to/from that physical address by dereferencing ptr. If you want to read/write to a memory location in asssembly you have to deference this too (generic CISC dialect: ptr: .dword 0x100h and then use mov ax, 0[ptr]). Are we talking cross purposes here? – cdcdcd Jan 10 '17 at 10:03
  • Why I ask, is that I can't believe what you're saying as an experienced programmer. If you are compiling at a system level the compiler doesn't care and you can force it to accept hard coded address spaces - this will be preserved right down to the machine code. How memory is accessed is ultimately down to the software implementation. In modern OS this is managed into virtual memory - even at a kernel level (even if it is just an offset mapping). But that does not mean C code can not be hard coded with physical memory addresses. – cdcdcd Jan 10 '17 at 10:09
  • @cdcdcd: No, what I'm trying to tell you is, that the *C language standard* does not know or care about something called "physical memory addresses". It doesn't for the simple reason that C has been written in a way, that it can be used across any conceivable kind of computer architecture. It's perfectly possible to build machines that don't operate on flat, linear memory, but organize data in higher level structures (like the CAR/CDR lists of LISP, or a hardware level dictionary implementation). It's up to the compiler to (i.e. the implementation) to actually decide on the actual data layout. – datenwolf Jan 10 '17 at 10:43
  • @cdcdcd: When it comes to the actual implementation (i.e. compilers) some implementations may actually specify in a well defined matter, that physical or virtual memory address locations are allowed to be cast to a pointer. But think about the following: The C language standard **mandates(!!!)** that arithmetic zero when cast to a pointer *always* casts to a null pointer; so it's *impossible* to validly access memory address 0x0. But quite a lot of machines have meaningful stuff there. You see where the problem is? Oh and FYI, you misuse the term DMA up there. – datenwolf Jan 10 '17 at 10:46
  • danten you're getting a bit prickly. I'm only having a discussion. I have been taking exception to your erroneous point that you cannot get direct access to physical memory using C. Everything you claim about C is true of assembly. The big difference in C and assembly is access to the instruction pointer. you need to be able to access the instruction address register. That is it. The C standard only determines the rules of how the symbolic code is converted to machine instructions. From their, the OS kernel and run-time determines everything else. But that is governed by the OS implementation! – cdcdcd Jan 10 '17 at 11:04
  • On a simple embedded system this layer is paper thin. And yes it does require assembly at the very start for the reasons I've given. But if the compiled C refers to physical addresses those addresses will be used. And yes C can point to 0x0 (although not advisable), but on modern systems the kernel throws an exception because there is TLB miss (no mapping) and the kernel has no record of it being buffered; it is the software that manages this on modern OS (and doesn't have to). On a small embedded system with NO MAPPING there is no exception of this nature and you can access that locality. – cdcdcd Jan 10 '17 at 11:27
  • FYI, I cut my teeth on 8bit systems so I know what and how a DMA works. It allows you to read and write to and from RAM and IO without any need for the CPU to be involved. And yes you can do this in C using direct memory mappings. – cdcdcd Jan 10 '17 at 11:28
  • @cdcdcd: Okay, here's some food for thought: How do you read from memory location 0x00 on an 8-bitter using *just* C? You can't do `char *p = (char*)0x00; char v = *p;`, because that would invoke undefined behaviour and an optimizing compiler may legally translate this into *anything*. – datenwolf Jan 10 '17 at 15:44
  • 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 Jan 10 '17 at 16:37
  • I need to add that when writing a compiler for particular fixed-system any address space for "stack" will start at a pre-ordained address and while you may be able to access it, it should not be used for explicit read/write operations. Back in the day you could do this for most systems, and this caused all sorts of chaos! Hence the emergence of things like MMUs. – cdcdcd Jan 10 '17 at 16:51
  • @cdcdcd: No you can't do `char *p=0; char c=*p;`. Doing this **always** invokes undefined behavior… *no exceptions!* And MMUs were introduced not just because of stack clobbering (if you wanted just that a mere MPU would be enough). MMUs give much more than just a virtual address space. – datenwolf Jan 10 '17 at 20:22
  • BTW, you have a habit of putting words into my mouth. I never said the MMU came into being because of stack issues. Look at said expression and note stack in quotations. The point being made that in a single, flat memory space you could pretty much access any part of the memory without having (or on purpose) any idea where local variables will be stored. In short, all this tiresome. MMU provide hardware protection and permissions among other things. If you cannot admit what your wrong on one bloody point - despite a whole body of 8/16bit system work - then there seems little point continuing. – cdcdcd Jan 10 '17 at 20:45
  • Undefined behaviour simply means that an expression will result in code that is not prescribed by a language's specifications (the standard if you will). It simply means, given the standard, all bets are off unless you KNOW that a given compiler plays ball. However, for a given environment it can be totally valid and will not be undefined for a given compiler implementation. But don't take my word for it, please read many of the answer from your peers here (in particular those related to embedded systems): http://stackoverflow.com/questions/21104702/dereferencing-a-pointer-to-0-in-c – cdcdcd Jan 10 '17 at 20:51
  • @cdcdcd: what you described is **implementation _defined_** behaviour. This is something different than *undefined* behaviour. Dereferencing a nullpointer is undefined behaviour and it is in fact illegal for an implementation to redefine that as implementation defined. – datenwolf Dec 06 '17 at 10:52
  • Question has tag "windows", so it assumes architecture-dependent calls and your answer is pointless. -1 –  Jan 09 '18 at 14:57
5

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

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

Shawnone
  • 850
  • 5
  • 17
  • 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 Dec 06 '11 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);
}
  • Works perfectly under Administrator privileges, and root respectively –  Dec 19 '17 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 :) –  Dec 21 '17 at 01: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. –  Dec 21 '17 at 03: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++.

Timmah
  • 177
  • 1
  • 2
  • 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. – gnometorule Dec 06 '11 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.

ahoward
  • 81
  • 4
-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.

M S
  • 3,995
  • 3
  • 25
  • 36
  • 1
    It's possible both from POSIX - /dev/mem and from Windows NtOpenSection(L"\\Device\\PhysicalMemory") –  Jan 12 '17 at 10:52
-3

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.

Martin York
  • 257,169
  • 86
  • 333
  • 562