使用PTRACE_SINGLESTEP仅截获系统调用
我们有一个学校项目,我们需要重新编码“strace” 我们只能截获系统调用,比如写和读,但不能使用使用PTRACE_SINGLESTEP仅截获系统调用,c,ptrace,C,Ptrace,我们有一个学校项目,我们需要重新编码“strace” 我们只能截获系统调用,比如写和读,但不能使用PTRACE\u系统调用。我正在寻找一种使用PTRACE\u SINGLESTEP实现这一点的方法,我已经编写了一种打印系统调用的方法,当我使用PTRACE\u syscall时,它工作得很好,但是当我使用PTRACE\u SINGLESTEP时,我找不到只打印系统调用的方法 这是我使用的代码,也许有人能帮我找出它的错误: pid_t child; long orig_eax; user_regs_
PTRACE\u系统调用
。我正在寻找一种使用PTRACE\u SINGLESTEP
实现这一点的方法,我已经编写了一种打印系统调用的方法,当我使用PTRACE\u syscall
时,它工作得很好,但是当我使用PTRACE\u SINGLESTEP
时,我找不到只打印系统调用的方法
这是我使用的代码,也许有人能帮我找出它的错误:
pid_t child;
long orig_eax;
user_regs_struct regs;
child = fork();
if (child == 0) {
ptrace(PTRACE_TRACEME, 0, 0, 0);
execve("/home/architek/a.out", {"/home/architek/a.out", NULL}, envp);
} else {
waitpid(child, &status, 0);
while (WIFSTOPPED(status)) {
orig_eax = ptrace(PTRACE_PEEKUSER, child, 8 * ORIG_RAX, NULL);
ptrace(PTRACE_GETREGS, child, NULL, ®s);
call_printer(®s, child);
ptrace(PTRACE_SINGLESTEP, child, 0, 0);
waitpid(child, &status, 0);
}
}
如果无法在系统调用之前/之后使用
PTRACE\u SYSCALL
停止子系统,则必须手动检测何时即将发生。我怀疑检查strace
的源代码是否有帮助,因为strace
很可能使用PTRACE\u SYSCALL
,没有理由手动解码指令
假设您正在使用x86-64,以下是您可以使用的方法:
PTRACE\u SINGLESTEP
,一次只执行一条指令PTRACE\u peek text
获取指令指针指向的下一条指令syscall
指令:0x0f 0x05
。由于x86是小端,这意味着检查ptrace(ptrace_PEEKDATA,…)
的返回值是否将两个最低有效字节设置为0x050f
int0x80
(操作码0xcd0x80
)完成的。查看列表
下面是一个例子:
#包括
长操作码;
// ...
waitpid(子级和状态,0);
while(WIFSTOPPED(状态)){
ptrace(ptrace_GETREGS、child、NULL和regs);
errno=0;
操作码=ptrace(ptrace_PEEKTEXT,child,regs.rip,0);
if(操作码==-1&&errno!=0){
perror(“ptrace(ptrace_PEEK_数据)失败”);
出口(1);
}
if((无符号长)操作码&0xffff==0x050f){
//将要执行syscall指令的子级,
//查看注册表以了解更多。。。
}
ptrace(ptrace_SINGLESTEP,child,0,0);
waitpid(子级和状态,0);
}
如果无法在系统调用之前/之后使用PTRACE\u SYSCALL
停止子系统,则必须手动检测何时即将发生。我怀疑检查strace
的源代码是否有帮助,因为strace
很可能使用PTRACE\u SYSCALL
,没有理由手动解码指令
假设您正在使用x86-64,以下是您可以使用的方法:
PTRACE\u SINGLESTEP
,一次只执行一条指令PTRACE\u peek text
获取指令指针指向的下一条指令syscall
指令:0x0f 0x05
。由于x86是小端,这意味着检查ptrace(ptrace_PEEKDATA,…)
的返回值是否将两个最低有效字节设置为0x050f
int0x80
(操作码0xcd0x80
)完成的。查看列表
下面是一个例子:
#包括
长操作码;
// ...
waitpid(子级和状态,0);
while(WIFSTOPPED(状态)){
ptrace(ptrace_GETREGS、child、NULL和regs);
errno=0;
操作码=ptrace(ptrace_PEEKTEXT,child,regs.rip,0);
if(操作码==-1&&errno!=0){
perror(“ptrace(ptrace_PEEK_数据)失败”);
出口(1);
}
if((无符号长)操作码&0xffff==0x050f){
//将要执行syscall指令的子级,
//查看注册表以了解更多。。。
}
ptrace(ptrace_SINGLESTEP,child,0,0);
waitpid(子级和状态,0);
}
您是否阅读了的所有(神秘的)文档?另见和。顺便说一句,strace
是开源的,你可以研究它的源代码。请提供一些您可能需要查看的内容/usr/include/x86_64-linux-gnu/sys/user.h
我已经阅读了ptrace(2),但我没有发现任何可能有用的请求,或者可能我没有看到它如何有用,我已经找到了“ptrace_SYSEMU”,但这个主题也禁止它,我已经阅读了一些strace源代码,还将阅读更多,也许我会发现一些有用的东西;至于user.h
中的结构,我找不到任何东西可以帮助我确定tracee是否在系统调用时停止了。您是否阅读了所有的(神秘的)文档?另见和。顺便说一句,strace
是开源的,你可以研究它的源代码。请提供一些您可能需要查看的内容/usr/include/x86_64-linux-gnu/sys/user.h
我已经阅读了ptrace(2),但我没有发现任何可能有用的请求,或者可能我没有看到它如何有用,我已经找到了“ptrace_SYSEMU”,但这个主题也禁止它,我已经阅读了一些strace源代码,还将阅读更多,也许我会发现一些有用的东西;至于user.h
中的结构,我找不到任何东西可以帮助我判断tracee是否在系统调用时停止了。谢谢你的帮助,在系统调用之前停止tracee是正常的(我只是不得不使用一个长字符和字符[8]的联合来获取操作码,因为&不起作用),这是捕获aft的相同方法吗