Skip to content

Instantly share code, notes, and snippets.

@FergusInLondon
Created March 28, 2017 07:02
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save FergusInLondon/fec6aebabc3c9e61e284983618f40730 to your computer and use it in GitHub Desktop.
Save FergusInLondon/fec6aebabc3c9e61e284983618f40730 to your computer and use it in GitHub Desktop.
snoopy.c - process_vm_readv() demonstration.
/**
* snoopy.c - Snoop on another tasks memory.
* Fergus In London <fergus@fergus.london>
*
* This is a pretty basic demo of the process_vm_readv syscall, a syscall which
* provides a nicer interface than ptrace for accessing memory used by another
* task.
*
* To play with simply use `ps` to get a PID for the process you'd like to snoop
* on, and `pmap` for the relevant memory address.
*
* Wrote whilst eating a bagel during breakfast.. probably not the nicest code.
*
* Requires a Linux Kernel > 3.2.
* https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
*/
#define _GNU_SOURCE
#include <sys/uio.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(int argc, char **argv) {
if (argc < 3) {
printf("usage: %s <pid> <mem address> [len]\n", argv[0]);
printf(" <pid> - PID of process to target\n");
printf(" <mem> - Memory address to target\n");
printf(" [len] - Length (in bytes) to dump\n");
return -1;
}
// PARSE CLI ARGS
pid_t pid = strtol(argv[1], NULL, 10);
printf(" * Launching with a target PID of: %zd\n", pid);
void *remotePtr = (void *)strtol(argv[2], NULL, 0);
printf(" * Launching with a target address of 0x%llx\n", remotePtr);
size_t bufferLength = (argc > 3) ? strtol(argv[3], NULL, 10) : 20;
printf(" * Launching with a buffer size of %d bytes.\n", bufferLength);
// Build iovec structs
struct iovec local[1];
local[0].iov_base = calloc(bufferLength, sizeof(char));
local[0].iov_len = bufferLength;
struct iovec remote[1];
remote[0].iov_base = remotePtr;
remote[0].iov_len = bufferLength;
// Call process_vm_readv - handle any error codes
ssize_t nread = process_vm_readv(pid, local, 2, remote, 1, 0);
if (nread < 0) {
switch (errno) {
case EINVAL:
printf("ERROR: INVALID ARGUMENTS.\n");
break;
case EFAULT:
printf("ERROR: UNABLE TO ACCESS TARGET MEMORY ADDRESS.\n");
break;
case ENOMEM:
printf("ERROR: UNABLE TO ALLOCATE MEMORY.\n");
break;
case EPERM:
printf("ERROR: INSUFFICIENT PRIVILEGES TO TARGET PROCESS.\n");
break;
case ESRCH:
printf("ERROR: PROCESS DOES NOT EXIST.\n");
break;
default:
printf("ERROR: AN UNKNOWN ERROR HAS OCCURRED.\n");
}
return -1;
}
printf(" * Executed process_vm_ready, read %zd bytes.\n", nread);
printf("%s\n", local[0].iov_base);
return 0;
}
@FergusInLondon
Copy link
Author

$ gcc snoopy.c -o snoopy
$ ./snoopy
usage: ./snoopy <pid> <mem address> [len]
  <pid> - PID of process to target
  <mem> - Memory address to target
  [len] - Length (in bytes) to dump
$ ./snoopy 26831 0x00007efbf7fd7000 10
 * Launching with a target PID of: 26831
 * Launching with a target address of 0x7efbf7fd7000
 * Launching with a buffer size of 10 bytes.
 * Executed process_vm_ready, read 10 bytes.
����

@Frago9876543210
Copy link

To bypass permission checking you can exec sudo sysctl kernel.yama.ptrace_scope=0 in bash

@hammad2224
Copy link

bypass permission checking

How do we do this on Android what is the command for android?

@hammad2224
Copy link

Some of the address are removed from the process memory by the time you read them and you get this
case EFAULT:
printf("ERROR: UNABLE TO ACCESS TARGET MEMORY ADDRESS.\n");

This also cause Crouption of the stack
How do we check if the address exist in the process memory or not?

@Frago9876543210
Copy link

@hammad2224 you can try to use https://frida.re BTW

@mohitsharma-cpi
Copy link

mohitsharma-cpi commented Sep 7, 2020

I am getting


➜  Test sudo ./Snoop 39075 0x5567fd9922a0 135168
 * Launching with a target PID of: 39075
 * Launching with a target address of 0x5567fd9922a0
 * Launching with a buffer size of 135168 bytes.
 * Executed process_vm_ready, read 134496 bytes.
My Sample Text
➜  Test sudo ./Snoop 39075 0x5567fd992200 1351689
 * Launching with a target PID of: 39075
 * Launching with a target address of 0x5567fd992200
 * Launching with a buffer size of 1351689 bytes.
 * Executed process_vm_ready, read 134656 bytes.

I don't understand why is the program reading less than the input.
My range of heap from program is 5567fd992000-5567fd9b3000

@hammad2224
Copy link

@hammad2224 you can try to use https://frida.re BTW

is there any example where i could read the process memory using frida. as i tried to find the documentation but it does not state how i can provide an address and read the memory from that address.
can i use c++ NDK to call frida methods?
where can i find documentation or example for simply reading a process memory from a provided address

@JonathanREmery
Copy link

JonathanREmery commented Jun 17, 2021

I am getting


➜  Test sudo ./Snoop 39075 0x5567fd9922a0 135168
 * Launching with a target PID of: 39075
 * Launching with a target address of 0x5567fd9922a0
 * Launching with a buffer size of 135168 bytes.
 * Executed process_vm_ready, read 134496 bytes.
My Sample Text
➜  Test sudo ./Snoop 39075 0x5567fd992200 1351689
 * Launching with a target PID of: 39075
 * Launching with a target address of 0x5567fd992200
 * Launching with a buffer size of 1351689 bytes.
 * Executed process_vm_ready, read 134656 bytes.

I don't understand why is the program reading less than the input.
My range of heap from program is 5567fd992000-5567fd9b3000

The program is reading your whole range as you can see by the "* Executed process_vm_ready, read 134496 bytes.", it isn't printing it all out though because there is a null byte. Basically how printf knows the end of a string is because they are terminated with a null byte or \x00 so it will only print out all the data it reads up to the first null byte as it thinks that is the end of the string.

@SpieringsAE
Copy link

@Frago9876543210

To bypass permission checking you can exec sudo sysctl kernel.yama.ptrace_scope=0 in bash

Hey I'm having permission issues, but this line seems to not do anything for me, it gives me:

sysctl: cannot stat /proc/sys/kernel/yama/ptrace_scope: No such file or directory

Is this a kernel config or something that i am missing or perhaps something else?

@Frago9876543210
Copy link

Frago9876543210 commented Nov 29, 2022

@Frago9876543210

To bypass permission checking you can exec sudo sysctl kernel.yama.ptrace_scope=0 in bash

Hey I'm having permission issues, but this line seems to not do anything for me, it gives me:

sysctl: cannot stat /proc/sys/kernel/yama/ptrace_scope: No such file or directory

Is this a kernel config or something that i am missing or perhaps something else?

@SpieringsAE
What's linux is it? I tested this on x84_64 Ubuntu

@SpieringsAE
Copy link

SpieringsAE commented Nov 29, 2022

@Frago9876543210

I'm running debian 11 on an arm64 embedded linux system

https://askubuntu.com/questions/146160/what-is-the-ptrace-scope-workaround-for-wine-programs-and-are-there-any-risks

i found this page but I turned the process_vm_readv and process_vm_writev into a python library and when i try

:~# setcap cap_sys_ptrace=eip /usr/moduline/python/read_test.py
Failed to set capabilities on file `/usr/moduline/python/read_test.py' (Operation not supported)
The value of the capability argument is not permitted for a file. Or the file is not a regular (non-symlink) file

Okay I compiled snoopy, and that seems to work. so there seems to be an issue where my python module/shared library is not getting the right permissions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment