Source Code ReadProcessMemory for Linux equivalent

Hexui Undetected CSGO Cheats Sinkicheat PUBG Cheat

NTvalk

Hacker
Meme Tier VIP
Jul 6, 2013
499
3,108
8

This is for people that are new to Linux and generally game hacking/programming, code is written in C.
When one is coming from Windows he will probably be used to ReadProcessMemory, an easy to use function for reading memory in another process.
Well on Linux there is no readprocessmemory, but a function that gives you even more control called ptrace.


First we are going to include some some files and define some funciton prototypes.

LinuxMemory.h

C++:
#define _GNU_SOURCE

#ifndef LINUXMEMORY_H
#define LINUXMEMORY_H

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>


#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ptrace.h>
#include <sys/wait.h>

#include <fcntl.h>

#define PROC_DIRECTORY "/proc/"   
#define CASE_SENSITIVE    1
#define CASE_INSENSITIVE  0
#define EXACT_MATCH       1
#define INEXACT_MATCH     0

typedef struct LinuxProc_s{

    char*    ProcMemPath;
    pid_t    ProcId;

} LinuxProc_t;

int attach(LinuxProc_t target);
int detach(LinuxProc_t target);
int Read(LinuxProc_t Process, int32_t nsize, void* address, void* buffer);
int Write(int32_t nsize, void* address, void* buffer);
pid_t GetPIDbyName(const char* cchrptr_ProcessName, int intCaseSensitiveness, int intExactMatch);
int IsNumeric(const char* ccharptr_CharacterList);
LinuxProc_t LinuxProcFromID(pid_t pid);

#endif // LINUXMEMORY_H
/proc/ is the directory where all the process information is stored in linux, there is two ways to modify/read memory from another process. the first way is by reading the mem file and the second way is to use the ptrace function used for debugging.
We are going to use the ptrace mehtod because its easier, reading the mem file is harder because /proc/$pid/mem shows the contents of $pid's memory mapped the same way as in the process, i.e., the byte at offset x in the pseudo-file is the same as the byte at address x in the process. If an address is unmapped in the process, reading from the corresponding offset in the file returns EIO (Input/output error). For example, since the first page in a process is never mapped (so that dereferencing a NULL pointer fails cleanly rather than unintendedly accessing actual memory), reading the first byte of /proc/$pid/mem always yield an I/O error.
The way to find out what parts of the process memory are mapped is to read /proc/$pid/maps. But for now we will keep it at ptrace.

I created a LinuxProc_t structure to store all process specific stuff in one struct per process.
For now we will just add the mem file path (we arent gonna use it) and the process id.

LinuxMemory.c
C++:
#include "LinuxMemory.h"

int IsNumeric(const char* ccharptr_CharacterList)
{
    for ( ; *ccharptr_CharacterList; ccharptr_CharacterList++)
        if (*ccharptr_CharacterList < '0' || *ccharptr_CharacterList > '9')
            return 0;
    return 1;
}

int strcmp_ws(const char *s1, const char *s2, int intCaseSensitive)
{
    if (intCaseSensitive)
        return !strcmp(s1, s2);
    else
        return !strcasecmp(s1, s2);
}

int strstr_ws(const char* haystack, const char* needle, int intCaseSensitive)
{
    if (intCaseSensitive)
        return (int) strstr(haystack, needle);
    else
        return (int) strcasestr(haystack, needle);
}

pid_t GetPIDbyName(const char* cchrptr_ProcessName, int intCaseSensitiveness, int intExactMatch)
{
    int ipid = -1;
    char chrarry_CommandLinePath[800]  ;
    char chrarry_NameOfProcess[500]  ;
    char* chrptr_StringToCompare = NULL ;
    struct dirent* de_DirEntity = NULL ;
    DIR* dir_proc = NULL ;

    int (*CompareFunction) (const char*, const char*, int) ;

    if (intExactMatch)
        CompareFunction = &strcmp_ws;
    else
        CompareFunction = &strstr_ws;


    dir_proc = opendir(PROC_DIRECTORY) ;
    if (dir_proc == NULL)
    {
        perror("Couldn't open the " PROC_DIRECTORY " directory") ;
        return  -2 ;
    }

    // Loop while not NULL
    while ((de_DirEntity = readdir(dir_proc)) )
    {
        // Skip non numeric entries
        if (de_DirEntity->d_type == DT_DIR)
        {
            if (IsNumeric(de_DirEntity->d_name))
            {
                strcpy(chrarry_CommandLinePath, PROC_DIRECTORY) ;
                strcat(chrarry_CommandLinePath, de_DirEntity->d_name) ;
                strcat(chrarry_CommandLinePath, "/cmdline") ;
                FILE* fd_CmdLineFile = fopen (chrarry_CommandLinePath, "rt") ;  // open the file for reading text
                if (fd_CmdLineFile)
                {
                    fscanf(fd_CmdLineFile, "%s", chrarry_NameOfProcess) ; // read from /proc/<NR>/cmdline
                    fclose(fd_CmdLineFile);  // close the file prior to exiting the routine

                    if (strrchr(chrarry_NameOfProcess, '/'))
                        chrptr_StringToCompare = strrchr(chrarry_NameOfProcess, '/') +1 ;
                    else
                        chrptr_StringToCompare = chrarry_NameOfProcess ;

                    if ( CompareFunction(chrptr_StringToCompare, cchrptr_ProcessName, intCaseSensitiveness) ) 
                    {
                        ipid = atoi(de_DirEntity->d_name);
                        closedir(dir_proc) ;
                        return ipid;
                    }
                }
            }
        }
    }
    closedir(dir_proc) ;
    return ipid ;
}

int attach(LinuxProc_t target)
{
    int status;

    /* attach, to the target application, which should cause a SIGSTOP */
    if (ptrace(PTRACE_ATTACH, target, NULL, NULL) == -1L) {
        fprintf(stderr, "error: failed to attach to %d, %s, Try running as root\n", target,
                strerror(errno));
        return 0;
    }

    /* wait for the SIGSTOP to take place. */
    if (waitpid(target, &status, 0) == -1 || !WIFSTOPPED(status)) {
        fprintf(stderr,
                "error: there was an error waiting for the target to stop.\n");
        fprintf(stdout, "info: %s\n", strerror(errno));
        return 0;
    }

    /* everything looks okay */
    return 1;

}

int detach(LinuxProc_t target)
{
    return ptrace(PTRACE_DETACH, target, NULL, 0) == 0;
}

int Read(LinuxProc_t Process, int32_t nsize, void* address, void* buffer)
{
    long  _DEBUGINT  = 0;

    _DEBUGINT = ptrace(PTRACE_PEEKDATA,Process.ProcId,address,0);
    printf("Output from ptrace : %i", _DEBUGINT); // currently just reads one word, but later i will add more data types.

    return 1;
}


LinuxProc_t LinuxProcFromID(pid_t pid)
{
    char mem_file_name[1000];
    LinuxProc_t ProcStruct;


    sprintf(mem_file_name, "/proc/%d/mem", pid);

    ProcStruct.ProcId = pid;
    ProcStruct.ProcMemPath = mem_file_name;

    return ProcStruct;
}

As you can see i created two wrapper functions for strstr and strcmp. Ive also added a function that checks if a string is numeric or not by checking if its between byte '0' and '9'.
What we need to do first is find the process id by name:
- loop through every file in /proc/
- check if the process has an id
- get the command line for the process (what was used to start the program)
- the cmdline contains the procname

then all we need to do is use ptrace on the process with PTRACE_PEEKDATA, which returns one word.

An example of usage:
main.c
C++:
#include <stdio.h>
#include <stdlib.h>

#include "LinuxMemory.h"

int main()
{
    LinuxProc_t CodeBlocks;
    /* Fill structure */
    CodeBlocks = LinuxProcFromID((pid_t)GetPIDbyName("codeblocks",0,0));
    printf("Process ID : %i\n", CodeBlocks.ProcId);
    void* address = 0x8b6b3000;
    attach(CodeBlocks);
    Read(CodeBlocks,0,address,0);
    detach(CodeBlocks);
    return 0;
}

Hope this helped some people out.
Peace.

 
Last edited:

Nether

The Angel Of Verdun
Meme Tier VIP
Dank Tier Donator
Dec 11, 2013
293
3,738
16
very nice dude, now i may be tempted to install a version of linux on my laptop :D
 
Attention! Before you post:

Read the How to Ask Questions Guide
99% of questions are answered in the Beginner's Guide, do it before asking a question.

No Hack Requests. Post in the correct section.  Search the forum first. Read the rules.

How to make a good post:

  • Fill out the form correctly
  • Tell us the game name & coding language
  • Post everything we need to know to help you
  • Ask specific questions, be descriptive
  • Post errors, line numbers & screenshots
  • Post code snippets using code tags
  • If it's a large project, zip it up and attach it

If you do not comply, your post may be deleted.  We want to help, please make a good post and we will do our best to help you.

Community Mods