-
-
Save FergusInLondon/fec6aebabc3c9e61e284983618f40730 to your computer and use it in GitHub Desktop.
/** | |
* snoopy.c - Snoop on another tasks memory. | |
* Fergus In London <[email protected]> | |
* | |
* 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
commented
Mar 28, 2017
To bypass permission checking you can exec sudo sysctl kernel.yama.ptrace_scope=0
in bash
bypass permission checking
How do we do this on Android what is the command for android?
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?
@hammad2224 you can try to use https://frida.re BTW
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 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
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.
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?
To bypass permission checking you can exec
sudo sysctl kernel.yama.ptrace_scope=0
in bashHey 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
I'm running debian 11 on an arm64 embedded linux system
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
Sorry to bother you. There is one thing in the code that I don't quite understand: why is the value of liovcnt
equal to 2 when calling process_vm_readv
? Shouldn't it be 1?