【问题标题】:weird behavior setting RIP with ptrace使用 ptrace 设置 RIP 的奇怪行为
【发布时间】:2016-06-24 05:39:25
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: linux assembly ptrace


    【解决方案1】:

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

    我以与您相同的方式解决了这个问题(总是添加一个小的 nop-sled 并递增 RIP)。

    【讨论】:

    • 你能解释一下为什么内核在继续调用时必须减去系统调用的 sizeof 吗?谢谢!
    • 我认为这是 RESTART 处理的一部分。你通过发送一个信号来阻止它。如果内核希望在信号处理程序完成后重新启动系统调用,它需要回到内核。它通过确保您将再次运行“系统调用”指令来做到这一点。
    猜你喜欢
    • 2012-09-30
    • 1970-01-01
    • 2014-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多