1

I'm trying to get the values stored in my computer's memory addresses. For that, I've written a little C++ program, but it throws a Read access violation error when trying to get the value stored in the address 0x1.

The goal here is to get the values that can be retrieved, not the ones that can't.

Anyways, here's the code:

#include <iostream>
#include <conio.h>

using namespace std;

int main() {
    unsigned long long *ptr1;
    for (unsigned long long i = 0; i < 0xFFFFFFFF; i++)
    {
        try {
            ptr1 = reinterpret_cast<unsigned long long*>(i);
        }
        catch (...) {
            cout << "Some erros happened" << endl;
        }

        if (ptr1 != nullptr) {
            try {
                cout << "Value in address 0x" << i << ": " << *ptr1 /*Error here*/ << endl;
            }
            catch(...) {
                cout << "Some erros happened" << endl;
            }
        }
        else {
            cout << "Value in address 0x" << i << ": null pointer" << endl;
        }

    }
    _getch();
    return 0;
}

Note that in the first iteration of the for loop the program detects that ptr1 is a null pointer but in the second one, the program crashes when it gets to *ptr1.

If I'm not mistaken, I think the error comes from *ptr1 not being able to read what's stored in that address, but I don't know how to know that without actually referencing ptr1.

Apparently, the try catch blocks cannot be used in this situation.

By the way, this is the output of the program:

Value in address 0x0: null pointer Value in address 0x1:

Then it throws the error.

Garmekain
  • 321
  • 2
  • 9
  • 9
    You may be surprised to learn that there's more than one operating system used on all computers in the world, and each operating system manages process memory differently, so it is not logically possible to answer this question without knowing what the host C++ implementation is. Furthermore, with modern operating systems you do not get to access the actual hardware RAM directly; rather the process runs in virtual memory address space. Even if you were to obtain your OS's virtual memory map, all you'll see is your own process's virtual memory. – Sam Varshavchik Jun 06 '16 at 12:11
  • 3
    why ? what are you trying to achieve ? – Sander De Dycker Jun 06 '16 at 12:12
  • On a modern OS, a process can only access its own virtual memory. If you are running Linux, you can access the RAM via `/dev/mem` (you have to be root for that), on Windows there might be something similar. – Karsten Koop Jun 06 '16 at 12:15
  • @SamVarshavchik Sorry, forgot to add a windows tag. – Garmekain Jun 06 '16 at 12:16
  • 2
    Why do you "detect" a null pointer? Are you not interested in what is at address 0? Also 0x1 is not a valid `unsigned long long *`, wrong alignment. – nwp Jun 06 '16 at 12:18
  • 2
    if the OS would allow this it would constitute a serious security problem, you only get to read the virtual address space of your own process. – AndersK Jun 06 '16 at 12:21
  • @nwp Getting the value of a null pointer gives me an error, so I didn't want that. – Garmekain Jun 06 '16 at 12:25
  • On some platforms, such as an embedded system, a program may have access to the entire address space. The underlying hardware would determine which addresses are valid and can be read or written to. – Thomas Matthews Jun 06 '16 at 12:32
  • conio.h? Did I time travel to 1980 and not notice? – Lightness Races in Orbit Jun 06 '16 at 12:38
  • @LightnessRacesinOrbit If you know another way of closing the program when a key is character key is pressed, please tell me. I also hate conio.h, because I only use it for that. – Garmekain Jun 06 '16 at 12:42
  • @Garmekain: You can use standard facilities ... but the best way of doing that is _to not do that_! http://stackoverflow.com/a/36374595/560648 – Lightness Races in Orbit Jun 06 '16 at 12:43
  • a null pointer gives error, so does an invalid address like 0x1 – phuclv Jun 06 '16 at 12:53
  • There's a lot more to this than you think (guard pages, page protection, 64-bit applications, ...). At any rate, this very much sounds like an [XY question](http://meta.stackexchange.com/q/66377/205381). What are you **really** trying to solve? – IInspectable Jun 06 '16 at 12:58
  • to pause the program there are tons of solutions you can find with a simple search [How to stop C++ console application from exiting immediately?](http://stackoverflow.com/q/2529617/995714), [How to pause in C?](http://stackoverflow.com/q/4869507/995714) – phuclv Jun 06 '16 at 12:58

3 Answers3

3

There is no technique to do it in a way that is legal from the C++ standard's point of view. According to the standard, the only way to know that a memory location can be accessed is to make sure that it has been allocated to your program. In other words, your pointer needs to point to an address of one of your global / static / local variables, or a block that has been allocated using malloc functions.

All other addresses are off-limits to your program. If you access them, your system is allowed to do anything it wants, from returning invalid values to terminating the program.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • So a program can only access memory used by that program? – Garmekain Jun 06 '16 at 12:22
  • A program will only have access to its own address space in a modern operating system. – drescherjm Jun 06 '16 at 12:25
  • On some platforms, such as embedded systems, a program can have access to the entire address space. The validity of an address is defined by the hardware; not all addresses may be available or have memory allocated to them (some could be hardware devices such as a USB controller). – Thomas Matthews Jun 06 '16 at 12:30
  • OP's goal : `The goal here is to get the values that can be retrieved, not the ones that can't.` So even if I do not use any of global / static / local variables or buffer that has been `malloc`ed then also there are many addresses which I can access. I guess OP wants to know regarding such addresses. – sameerkn Jun 06 '16 at 12:34
0

for (unsigned long long i = 0; i < 0xFFFFFFFF; i++) from this for loop it seems that you are trying to access complete virtual address space of process.

So you can try by first finding the page size used in process. Then you can try Locking that page. Some APIs are available in Windows. Depending upon the result you will come to know which range of addresses are restricted.

VirtualLock function

sameerkn
  • 2,209
  • 1
  • 12
  • 13
  • What do you mean by "page"? – Garmekain Jun 06 '16 at 12:19
  • By page i mean the virtual page. Your virtual address space is divided into X number of pages. X = [total_virtual_address] / [page_size]. – sameerkn Jun 06 '16 at 12:30
  • `VirtualLock` does something **completely** different, and it can fail for reasons other than inability to read the virtual memory. [VirtualQuery](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366902.aspx) is more appropriate, while still wrong. Anyway, -1, sorry. – IInspectable Jun 06 '16 at 13:02
0

I played around with signals and catching SIGSEGV. Note that this example is very (I'm saying again, very) bad example, it isn't even legal (in terms of C(++) standard), but it just Works™. I tested it with 2 (local) variables and it seems to work.

Also, don't forget that this won't print values in your (physical) memory. Usually, your program gets a virtual address space where virtual address doesn't have to match with physical address. So, you won't see contents of memory addresses of other processes, you'll see only yours.

#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <conio.h>


jmp_buf jumpBuffer;

void sig(int ignore)
{
    signal(SIGSEGV,sig); //to prevent reseting signal action back to SIG_DFL (default)
    longjmp(jumpBuffer,1); //jump back to setjmp() and correct our mistakes
}

int main()
{
    signal(SIGSEGV,sig);

    unsigned int a = 0x123456;
    unsigned int b = 0x876543;

    printf("a (%x) resides at %p \n",a,&a);
    printf("b (%x) resides at %p \n",b,&b);
    getch();

    static const long max = 0xFFFFFFFF;
    int *i = 0; //This is tricky, null pointer constant doesn't need to be represented as zero
    for (;(long)i < max;i++) //these pointer-to-integer casts are also implementation-specific
    {

        //if jmp was made to setjmp, returned value is specified as second parameter in longjmp
        //if this is regular call, not jump, returned value is zero
        if (setjmp(jumpBuffer) == 0) 
            printf("Address %p contains %x \n",i,*i); //if this fails, SIGSEGV is raised and sent to our handler
        else
            printf("Address %p is invalid \n",i);

    }
}
PcAF
  • 1,975
  • 12
  • 20