I'm trying to redirect a tracee's stdout to a file.
For this I've:
To reach these results I had to dig myself into this repository.
So far my results look good, I'm ptracing into a top
command, and lsof
can detect my effort (see last line):
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
top 421762 root cwd DIR 179,2 4096 17528 /root
top 421762 root rtd DIR 179,2 4096 2 /
top 421762 root txt REG 179,2 124856 12493 /usr/bin/top
top 421762 root 0u CHR 136,1 0t0 4 /dev/pts/1
top 421762 root 1u CHR 136,1 0t0 4 /dev/pts/1
top 421762 root 2w CHR 1,3 0t0 5 /dev/null
top 421762 root 3u CHR 136,1 0t0 4 /dev/pts/1
top 421762 root 4r REG 0,17 0 4026533347 /proc/stat
top 421762 root 5r REG 0,17 0 4026533348 /proc/uptime
top 421762 root 6r REG 0,17 0 4026533346 /proc/meminfo
top 421762 root 7r REG 0,17 0 4026533345 /proc/loadavg
top 421762 root 8u FIFO 0,28 0t0 827 /tmp/mystdout
And this is my command's output (just for completeness):
[+] Allocated scratch page: 7fbd357000
[+] Opened the new fd in the child: 8 (/tmp/mystdout)
[+] Saved fd 1 to -1 in the child
[+] Duplicated fd 8 to 1
[+] Freed scratch page: 7fbd357000
What I'm trying to do now is the final step, which is to dup2
the stdout of the tracee to the opened file_fd (8).
I wrote a very small program to test how dup2
works on the target platform (aarch64):
int i = 0;
while(1) {
printf("helloworld %d\n", i++);
sleep(1);
if (i==5) {
printf("Opening tmp file\n");
int file_fd = open("/tmp/mystdout", O_RDWR | O_CREAT, 0666, 0, 0);
printf("File opened=%d\n", file_fd);
int err = dup2(file_fd, 1);
printf("dup2 result=%d\n", err);
close(file_fd);
}
}
This test program verified that I can close the file_fd after the dup2 call and still the program will continue logging to this file by default. Even my "dup2 result=1" is printed into the file (and not onto stdout ).
Considering dup2 's return value of 1 matches with its expected behavior by its documentation:
On success, these system calls return the new file descriptor.
After verified dup2 is working if called directly, I'm calling dup2
now with ptrace in the tracee with arguments of file_fd
(8) and orig_fd
(1):
int err = do_syscall(child, dup2, file_fd, orig_fd, 0, 0, 0, 0);
debug("Duplicated fd %d to %d, return=%d", file_fd, orig_fd, err);
With this, the program's output changes to this:
[+] Allocated scratch page: 7fbd357000
[+] Opened the new fd in the child: 8 (/tmp/mystdout)
[+] Saved fd 1 to -1 in the child
[+] Duplicated fd 8 to 1, return=8 !!!
[+] Freed scratch page: 7fbd357000
As you can see, dup2 is executed successfully (positive return value), BUT it returned with 8 instead of 1 .
Again, I'm calling ptraced dup2 with this method:
int err = do_syscall(child, dup2, 8, 1, 0, 0, 0, 0);
I don't know how could I detail this method here as it's a bit too large, but for reference here is how I called openat which actually opened the desired file in tracee's process:
int file_fd = do_syscall(child, openat, AT_FDCWD, scratch_page, O_RDWR | O_CREAT, 0666, 0, 0);
(Note: scratch_page is a memory mapped in tracee's space, and "/tmp/mystdout" is copied into it before using this instruction above)
So the question is:
How can I debug the injected dup2? For example with strace ?
I wish to understand why it behaves different than when called directly from the small test application.
It turned out that on aarch64
for some reason, dup2
is not able to injected.
No matter what I've tried, it always returned with weird results.
However after I changed dup2
to dup3
everything magically started working.
I'm still wondering on why dup2
syscall can't work, but for now after days of digging and learning I'm happy with this result.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.