ptrace(PTRACE_PEEKDATA, ...) error: data dump
ptrace(PTRACE_PEEKDATA, ...) error: data dump
我想从 运行 进程获取指令并使用 ptrace 更改它。当变量 instr(包含当前指令 - PTRACE_PEEKDATA)未签名时一切正常,但当我将其更改为 long int 时出现错误(内存转储)。 ptrace(PTRACE_PEEKDATA, ...) returns long int 所以这应该不是问题。我在 Ubuntu.
上工作
我哪里弄错了?我是新手,所以这可能会有些愚蠢。
我的代码:
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/types.h>
#include <stdlib.h>
#include <wait.h>
int main()
{
int status;
char *pid_char;
pid_t PID;
struct user_regs_struct reg; /* register */
long int instr;
unsigned changedInstr;
printf("Tracee PID: ");
scanf("%s", pid_char);
PID = atoi(pid_char);
printf("\n");
/* PTRACE STARTS */
ptrace(PTRACE_ATTACH, PID, NULL, NULL);
waitpid(PID, &status, 0);
ptrace(PTRACE_GETREGS, PID, NULL, ®);
instr = ptrace(PTRACE_PEEKDATA, PID, reg.rip, NULL);
printf("Current Instruction: %llx\n", instr);
scanf("%u", &changedInstr);
ptrace(PTRACE_POKEDATA, PID, reg.rip, &changedInstr);
ptrace(PTRACE_DETACH, PID, NULL, NULL);
return 0;
}
On x86_64、PTRACE_PEEKDATA
returns 8 个字节和 PTRACE_POKEDATA
从其 addr
参数指向的地址开始传输 8 个字节。 使用 long 或 unsigned long 应该没问题。
如果附加到 nanosleep
系统调用中的进程,指令流如下所示:
(gdb) disass /r
Dump of assembler code for function __nanosleep_nocancel:
0x00007ffff7ad92e9 <+0>: b8 23 00 00 00 mov [=10=]x23,%eax
0x00007ffff7ad92ee <+5>: 0f 05 syscall
=> 0x00007ffff7ad92f0 <+7>: 48 3d 01 f0 ff ff cmp [=10=]xfffffffffffff001,%rax
0x00007ffff7ad92f6 <+13>: 73 31 jae 0x7ffff7ad9329 <nanosleep+73>
0x00007ffff7ad92f8 <+15>: c3 retq
执行后instr = ptrace(PTRACE_PEEKDATA, PID, reg.rip, NULL);
,
instr
如果是无符号长整型则为 3173fffff0013d48
,如果为无符号长整型则为 f0013d48
。
在你的程序中,changedInstr
是无符号的,ptrace(PTRACE_POKEDATA, PID, reg.rip, &changedInstr);
将传输 changedInstr
的 4 个字节,然后是堆栈上与其相邻的 4 个字节,可能是其他局部变量的一部分。如您所见,这 4 个字节可能是无害的或会使目标进程出现异常的东西。
在这种情况下,如果您想在 reg.rip
处写入一条 4 字节指令,应该是
unsigned changedInstr;
...
instr = ptrace(PTRACE_PEEKDATA, PID, reg.rip, NULL);
scanf("%u", &changedInstr);
instr = (instr & ~0xFFFFFFFFul) | changedInstr
ptrace(PTRACE_POKEDATA, PID, reg.rip, &instr);
我想从 运行 进程获取指令并使用 ptrace 更改它。当变量 instr(包含当前指令 - PTRACE_PEEKDATA)未签名时一切正常,但当我将其更改为 long int 时出现错误(内存转储)。 ptrace(PTRACE_PEEKDATA, ...) returns long int 所以这应该不是问题。我在 Ubuntu.
上工作我哪里弄错了?我是新手,所以这可能会有些愚蠢。
我的代码:
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/types.h>
#include <stdlib.h>
#include <wait.h>
int main()
{
int status;
char *pid_char;
pid_t PID;
struct user_regs_struct reg; /* register */
long int instr;
unsigned changedInstr;
printf("Tracee PID: ");
scanf("%s", pid_char);
PID = atoi(pid_char);
printf("\n");
/* PTRACE STARTS */
ptrace(PTRACE_ATTACH, PID, NULL, NULL);
waitpid(PID, &status, 0);
ptrace(PTRACE_GETREGS, PID, NULL, ®);
instr = ptrace(PTRACE_PEEKDATA, PID, reg.rip, NULL);
printf("Current Instruction: %llx\n", instr);
scanf("%u", &changedInstr);
ptrace(PTRACE_POKEDATA, PID, reg.rip, &changedInstr);
ptrace(PTRACE_DETACH, PID, NULL, NULL);
return 0;
}
On x86_64、PTRACE_PEEKDATA
returns 8 个字节和 PTRACE_POKEDATA
从其 addr
参数指向的地址开始传输 8 个字节。 使用 long 或 unsigned long 应该没问题。
如果附加到 nanosleep
系统调用中的进程,指令流如下所示:
(gdb) disass /r
Dump of assembler code for function __nanosleep_nocancel:
0x00007ffff7ad92e9 <+0>: b8 23 00 00 00 mov [=10=]x23,%eax
0x00007ffff7ad92ee <+5>: 0f 05 syscall
=> 0x00007ffff7ad92f0 <+7>: 48 3d 01 f0 ff ff cmp [=10=]xfffffffffffff001,%rax
0x00007ffff7ad92f6 <+13>: 73 31 jae 0x7ffff7ad9329 <nanosleep+73>
0x00007ffff7ad92f8 <+15>: c3 retq
执行后instr = ptrace(PTRACE_PEEKDATA, PID, reg.rip, NULL);
,
instr
如果是无符号长整型则为 3173fffff0013d48
,如果为无符号长整型则为 f0013d48
。
在你的程序中,changedInstr
是无符号的,ptrace(PTRACE_POKEDATA, PID, reg.rip, &changedInstr);
将传输 changedInstr
的 4 个字节,然后是堆栈上与其相邻的 4 个字节,可能是其他局部变量的一部分。如您所见,这 4 个字节可能是无害的或会使目标进程出现异常的东西。
在这种情况下,如果您想在 reg.rip
处写入一条 4 字节指令,应该是
unsigned changedInstr;
...
instr = ptrace(PTRACE_PEEKDATA, PID, reg.rip, NULL);
scanf("%u", &changedInstr);
instr = (instr & ~0xFFFFFFFFul) | changedInstr
ptrace(PTRACE_POKEDATA, PID, reg.rip, &instr);