Linux read and write external memory.

Hi everyone. I asked once here and it went well, so I'm very happy with this community.

I have a new question to ask. I would like to read&write specify memory of a process which is not the process I'm doing it from, nor a child nor a parent.

So, I want to do a program similar to Cheat Engine. I already have done the speed hack module (thank you unix.com!), and now I'm going to start with memory modifying part.

First of all, I need to know how to read (and write) bytes from (and to) another process. In windows API those are (Read)&(Write)ProcessMemory I guess.

Second, I need to know which are the readable regions so I can do a full snapshot of all the readable memory of an application.

If you need to know the OS target:

uname -a
Linux littleEzek-desktop 2.6.35-27-generic #48-Ubuntu SMP Tue Feb 22 20:25:46 UTC 2011 x86_64 GNU/Linux

Thank you again for read.

To mess with another process' memory in Linux you use ptrace as described here. This is the same way things like gdb do it. The obvious way to do so, /proc/pid/mem, won't work until you've connected with ptrace.

Getting the readable regions is a little more easy.

$ cat /proc/self/maps
00400000-0040b000 r-xp 00000000 08:05 264334                             /bin/cat
0060a000-0060b000 r--p 0000a000 08:05 264334                             /bin/cat
0060b000-0060c000 rw-p 0000b000 08:05 264334                             /bin/cat
01d91000-01db2000 rw-p 00000000 00:00 0                                  [heap]
7ffe71387000-7ffe714d7000 r-xp 00000000 08:05 264645                     /lib64/libc-2.11.2.so
7ffe714d7000-7ffe716d6000 ---p 00150000 08:05 264645                     /lib64/libc-2.11.2.so
7ffe716d6000-7ffe716da000 r--p 0014f000 08:05 264645                     /lib64/libc-2.11.2.so
7ffe716da000-7ffe716db000 rw-p 00153000 08:05 264645                     /lib64/libc-2.11.2.so
7ffe716db000-7ffe716e0000 rw-p 00000000 00:00 0 
7ffe716e0000-7ffe716fe000 r-xp 00000000 08:05 264632                     /lib64/ld-2.11.2.so
7ffe718d5000-7ffe718d8000 rw-p 00000000 00:00 0 
7ffe718fc000-7ffe718fd000 rw-p 00000000 00:00 0 
7ffe718fd000-7ffe718fe000 r--p 0001d000 08:05 264632                     /lib64/ld-2.11.2.so
7ffe718fe000-7ffe718ff000 rw-p 0001e000 08:05 264632                     /lib64/ld-2.11.2.so
7ffe718ff000-7ffe71900000 rw-p 00000000 00:00 0 
7fffba285000-7fffba2a7000 rw-p 00000000 00:00 0                          [stack]
7fffba3a3000-7fffba3a4000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
$

...where 'self' is 'self' to get cat's own memory, or any PID of your choosing.

---------- Post updated at 05:52 PM ---------- Previous update was at 05:50 PM ----------

I think the meaning of the columns is

beginning-end file_offset permissions ...

file_offset is only meaningful if it's actually a mapped file of course.

2 Likes

I'm getting in trouble trying to do this. Firstly, a c++ problem:

This is on memory.cpp (it got compiled):

template<class T>
bool peekValue(T * value, char * offset, pid_t pid)
{
    // Get /proc/$pid/mem
    char mem_file_name[255];
    sprintf(mem_file_name, "/proc/%d/mem", pid);
    // Opening /proc/$pid/mem
    FILE * mem_fd = fopen(mem_file_name, "r");
    // Tracing the app.
    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1)
        return false;
    // Force it to wait
    if (waitpid(pid, NULL, 0) == -1)
    {
        ptrace(PTRACE_DETACH, pid, NULL, NULL);
        return false;
    }
    // Move pointer to offset.
    fseek(mem_fd, (long int)offset, SEEK_SET);
    // Read from memory.
    fread(value, 1, sizeof(T), mem_fd);
    // End petrace.
    ptrace(PTRACE_DETACH, pid, NULL, NULL);
    return true;
}

and in main.cpp:

many includes after:

int main(int argc, char ** argv)
{
    programinfo pnfo;
    int m;
    long int offset = 0;

    ...
    cout << "Enter the PID of the program you want to hack" << endl;
    cin >> pnfo.pid;
    cout << "Enter the pointer to int you want to read" << endl;
    cin >> offset;
    pnfo.mem_blocks = getMemoryMemblocks(pnfo.pid);
    peekValue<int>(&m, (char*)offset, pnfo.pid);
    cout << m << endl;
    return 0;
}

Got error (from linker):

/home/***/proyectos/xeat_engine/main.cpp|22|undefined reference to `bool peekValue<int>(int*, char*, int)'|

So I changed it to:

/*template<class T>*/
bool peekValue(int * value, char * offset, pid_t pid)
{
    // Get /proc/$pid/mem
    char mem_file_name[255];
    sprintf(mem_file_name, "/proc/%d/mem", pid);
    // Opening /proc/$pid/mem
    FILE * mem_fd = fopen(mem_file_name, "r");
    // Tracing the app. This fails:
    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1)
        return false;
    // Force it to wait
    if (waitpid(pid, NULL, 0) == -1)
    {
        ptrace(PTRACE_DETACH, pid, NULL, NULL);
        return false;
    }
    // Move pointer to offset.
    fseek(mem_fd, (long int)offset, SEEK_SET);
    // Read from memory.
    fread(value, 1, sizeof(int), mem_fd);
    // End petrace.
    ptrace(PTRACE_DETACH, pid, NULL, NULL);
    return true;
}

And:

many includes after:

int main(int argc, char ** argv)
{
    programinfo pnfo;
    int m;
    long int offset = 0;

    ...
    cout << "Enter the PID of the program you want to hack" << endl;
    cin >> pnfo.pid;
    cout << "Enter the pointer to int you want to read" << endl;
    cin >> offset;
    pnfo.mem_blocks = getMemoryMemblocks(pnfo.pid);
    peekValue/*<int>*/(&m, (char*)offset, pnfo.pid);
    cout << m << endl;
    return 0;
}

It "works". Any idea about this?

The second question is that it "works". It means the function got executed but it doesn't do its job. It fails on ptrace attachment. I'm trying to ptrace pid 6000, which is the pid of neverball (a videogame of a ball), but it returns -1.

What are the conditions to do a ptrace? Any idea?

Thank you for read.

---------- Post updated at 04:55 PM ---------- Previous update was at 11:09 AM ----------

I've solved the above problem (super user privileges).

Now I'm wonder a thing. Is to write in /proc/pid/mem possible?

I'm not sure, but I do know it's wasteful to have 9 different kinds of functions that differ only in one way, size -- this is one of the really wasteful things about the C++ model, people forget how to write truly generic functions.

You shouldn't be using fopen() on raw devices either, you don't want them buffered by accident, use the basic system calls instead. Doesn't matter so much on read but could matter a lot on write. How about this?

/*template<class T>*/
bool peekValue(void *value, void *offset, size_t size, pid_t pid)
{
    // Get /proc/$pid/mem
    char mem_file_name[255];
    sprintf(mem_file_name, "/proc/%d/mem", pid);
    // Opening /proc/$pid/mem
    int fd=open(mem_file_name, O_RDWR);
    // Tracing the app. This fails:
    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1)
        return false;
    // Force it to wait
    if (waitpid(pid, NULL, 0) == -1)
    {
        ptrace(PTRACE_DETACH, pid, NULL, NULL);
        return false;
    }
    // Move pointer to offset.
    lseek(fd, (off_t)offset, SEEK_SET);
    // Read from memory.
    read(value, size, fd);
    // End petrace.
    ptrace(PTRACE_DETACH, pid, NULL, NULL);
    return true;
}

Ideally, you'd want to just attach to the process once and use the same fd over and over, too, though it'd naturally be more complicated starting and stopping the child etc etc etc.

I think the process either has to be a child of yours, or you have to be root. You might have more luck as a limited user if your own program launched the application with fork/exec.

Yes. Only to segments which allow writing of course. Beyond that there shouldn't be anything special about it. Of course the program may have optimized certain variables out for all you know and respond either badly or not at all to writes in certain places; hard to tell when you don't control the source!