使用 ptrace 设置 RIP 的奇怪行为

weird behavior setting RIP with ptrace

基本上,我使用ptrace 将shell 代码注入远程进程以供执行。但是我发现了一些关于 RIP 寄存器的奇怪行为。

我所做的是将我的 shell 代码复制到程序映射的起始地址。然后我使用 ptrace 将 RIP 设置为起始地址所在的地址。然后我恢复执行代码的目标进程。一旦 shell 代码完成(由 运行 int3),我将收到信号并恢复我刚刚修改的代码。

它工作正常,除非远程进程在像 sleep 这样的系统调用中被 阻塞 。如果在我附加进程时远程进程在系统调用内被阻塞,在我将 RIP 设置到我想要执行 shell 代码的位置然后恢复目标进程后,我将观察到 RIP实际上比我在 ptrace 调用中输入的地址少 2。例如,如果我将 RIP 设置为 0x4000,一旦我恢复它,RIP 将变为 0x3ffe。显然,由于段错误,我的情况通常会崩溃。但是如果我在设置后立即抓取寄存器而不恢复进程,那么 RIP 就是我刚刚设置的值。目前我通过在 shell 代码之前插入 2 个 nop 指令来解决这个问题,并且在设置 RIP 时总是添加 2 个。我只想知道我在设置 RIP 时是否遗漏了什么,或者我整个注入代码的方法是否完全不稳定?

我的开发箱是Ubuntu14.04,内核是3.13.0-45-generic。

如果我没记错的话,如果您在进程被系统调用阻塞时中断进程,程序计数器值在继续时将被内核减去 sizeof(syscall 指令)。因此,一旦您执行 PTRACE_DETACH,该进程将重新执行它被中断的系统调用。

我用和你一样的方法解决了这个问题(总是添加一个小的 nop-sled 和递增的 RIP)。