从手册页:
PTRACE_GET_SYSCALL_INFO(自Linux 5.3起)
检索导致停止的系统调用的信息。的信息放入data参数指向的缓冲区中,应该是指向struct类型的缓冲区的指针ptrace_syscall_info。 addr参数包含数据参数指向的缓冲区(即sizeof(structptrace_syscall_info))。返回值包含可供内核写入的字节数。如果大小内核要写入的数据超出了addr参数,输出数据将被截断。
>cat /proc/version
Linux version 5.3.0-kali2-amd64 ([email protected]) (gcc version 9.2.1 20191109 (Debian 9.2.1-19)) #1 SMP Debian 5.3.9-3kali1 (2019-11-20)
>
现在,我已经编写了这个小程序,由两个文件组成。
#ifndef HELPERS
#define HELPERS
//helpers.h
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/types.h>
const char* op_to_string(__u8 op)
{
switch (op) {
case (PTRACE_SYSCALL_INFO_ENTRY):
return "SYSCALL_INFO_ENTRY";
break;
case (PTRACE_SYSCALL_INFO_EXIT):
return "SYSCALL_INFO_EXIT";
break;
case (PTRACE_SYSCALL_INFO_SECCOMP):
return "SYSCALL_INFO_SECCOMP";
break;
default:
fprintf(stderr, "op-to-string: Invalid op code");
}
}
void err_wrap(const int ret, const int success, const char *msg)
{
if (ret != success)
{
perror(msg);
}
}
void print_regs(const struct user_regs_struct regs) {
printf ("r15: %16llx %30s\n", regs.r15, "general purpose registers");
printf ("r14: %16llx\n", regs.r14);
printf ("r13: %16llx\n", regs.r13);
printf ("r12: %16llx\n", regs.r12);
printf ("rbp: %16llx\n", regs.rbp);
printf ("rbx: %16llx\n", regs.rbx);
printf ("r11: %16llx\n", regs.r11);
printf ("r10: %16llx\n", regs.r10);
printf ("r9: %16llx %s\n", regs.r9, "6.");
printf ("r8: %16llx %s\n", regs.r8, "5.");
printf ("rax: %16llx\n", regs.rax);
printf ("rcx: %16llx %s\n", regs.rcx, "4.");
printf ("rdx: %16llx %s\n", regs.rdx, "3.");
printf ("rsi: %16llx %s\n", regs.rsi, "2.");
printf ("rdi: %16llx %30s\n", regs.rdi, "1. function/syscall argument"); // aka "parameter registers"
printf ("orig_rax:%16llx\n", regs.orig_rax);
printf ("rip: %16llx %30s\n", regs.rip, "instruction pointer");
printf ("cs: %16llx\n", regs.cs);
printf ("eflags: %16llx\n", regs.eflags);
printf ("rsp: %16llx %30s\n", regs.rsp, " Stack Pointer (current location in stack)");
printf ("ss: %16llx\n", regs.ss);
printf ("fs_base: %16llx\n", regs.fs_base);
printf ("gs_base: %16llx\n", regs.gs_base);
printf ("ds: %16llx\n", regs.ds);
printf ("es: %16llx\n", regs.es);
printf ("fs: %16llx\n", regs.fs);
printf ("gs: %16llx\n", regs.gs);
}
void print_syscall_info(struct ptrace_syscall_info sys_info) {
__u8 op = sys_info.op;
printf("Type of system call stop: %20s (%x)\n", op_to_string(op), op);
printf("Arch: %16llx\n", sys_info.arch);
}
#endif
#include <stdio.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <sys/user.h>
#include <syscall.h>
#include "helpers.h"
// long ptrace(enum __ptrace_request request, pid_t pid,
// void *addr, void *data);
void child_code();
void parent_code(pid_t pid);
int main(const int argc, char *argv[])
{
pid_t pid;
switch (pid = fork())
{
case -1:
perror("fork");
break;
case 0:
child_code();
break;
default: //parent code
parent_code(pid);
}
return 0;
}
void parent_code(pid_t pid)
{
printf("Parent code\n");
int status;
if (wait(&status) == -1)
{
perror("parent wait one");
}
printf("Finished waiting\n");
printf("PID wait status is: %llx\n", status);
printf("My PID is %d\n", getpid());
err_wrap(
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL),
0, "ptrace-set-options");
struct user_regs_struct regs;
struct ptrace_syscall_info syscall_info;
while(1)
{
err_wrap(ptrace(PTRACE_SYSCALL, pid, 0, 0), 0, "ptrace-syscall first"); //Stop at next syscall.
if (wait(&status) == -1)
{
perror("parent wait one");
}
printf("syscall-entry-stop\n");
err_wrap(
ptrace(PTRACE_GET_SYSCALL_INFO, pid, sizeof(struct ptrace_syscall_info), &syscall_info),
0, "ptrace-get-syscall-info");
err_wrap(
ptrace(PTRACE_GETREGS, pid, 0, ®s),
0,
"ptrace-getregs");
print_regs(regs);
print_syscall_info(syscall_info);
}
}
void child_code() {
printf("Child code\n");
printf("Parent is: %d\n", getppid());
err_wrap(ptrace(PTRACE_TRACEME, 0,0,0), 0, "ptrace-traceme");
err_wrap(raise(SIGSTOP), 0, "raise");
unsigned int pleb = 0xffbbcde8;
int x = 0;
printf("Hello WoRld\n");
printf("Pleb is: %llx\n", pleb);
printf("x is: %d\n", x);
}
考虑到所有问题,我的代码应该可以正常运行而不会出现错误,但是似乎好像实际上并未包含PTRACE_GET_SYSCALL_INFO的内容,因为gcc在抱怨:
>gcc -g -o tracetest tracetest.c
In file included from tracetest.c:10:
helpers.h:9:26: error: unknown type name ‘__u8’
9 | const char* op_to_string(__u8 op)
| ^~~~
helpers.h:72:32: warning: ‘struct ptrace_syscall_info’ declared inside parameter list will not be visible outside of this definition or declaration
72 | void print_syscall_info(struct ptrace_syscall_info sys_info) {
| ^~~~~~~~~~~~~~~~~~~
helpers.h:72:52: error: parameter 1 (‘sys_info’) has incomplete type
72 | void print_syscall_info(struct ptrace_syscall_info sys_info) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
helpers.h: In function ‘print_syscall_info’:
helpers.h:73:2: error: unknown type name ‘__u8’
73 | __u8 op = sys_info.op;
| ^~~~
helpers.h:74:54: warning: implicit declaration of function ‘op_to_string’ [-Wimplicit-function-declaration]
74 | printf("Type of system call stop: %20s (%x)\n", op_to_string(op), op);
| ^~~~~~~~~~~~
tracetest.c: In function ‘parent_code’:
tracetest.c:55:29: error: storage size of ‘syscall_info’ isn’t known
55 | struct ptrace_syscall_info syscall_info;
| ^~~~~~~~~~~~
tracetest.c:66:11: error: ‘PTRACE_GET_SYSCALL_INFO’ undeclared (first use in this function); did you mean ‘PTRACE_GETSIGINFO’?
66 | ptrace(PTRACE_GET_SYSCALL_INFO, pid, sizeof(struct ptrace_syscall_info), &syscall_info),
| ^~~~~~~~~~~~~~~~~~~~~~~
| PTRACE_GETSIGINFO
tracetest.c:66:11: note: each undeclared identifier is reported only once for each function it appears in
tracetest.c:66:48: error: invalid application of ‘sizeof’ to incomplete type ‘struct ptrace_syscall_info’
66 | ptrace(PTRACE_GET_SYSCALL_INFO, pid, sizeof(struct ptrace_syscall_info), &syscall_info),
| ^~~~~~
但是,如果我#include <linux/ptrace.h>
,那么我没有得到这些错误,但是它说的是函数ptrace.h的隐式声明,说实话,我认为也不是很好。
[应该为使此功能按预期包括的内容?我也包含了sys/types.h
,但是我仍然收到有关__u8
是未知类型名称的错误,但这是在ptrace.c源代码,因此它不应引发任何错误。
ptrace手册页的顶部说:
包括
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
因此,我本以为只有这个include就足够了,但是不起作用。
提前感谢。
这是因为glibc在所有最新的Linux功能上都不是最新的。您可以#include <linux/ptrace.h>
和#include <sys/ptrace.h>
获得PTRACE_GET_SYSCALL_INFO
。