linux - 在汇编中执行后如何将 execve 系统调用的输出返回到寄存器或堆栈?

标签 linux assembly system-calls shellcode execve

我正在用汇编语言编写,我正在尝试弄清楚如何执行 execve 系统调用,但我不想将输出打印到终端,而是想知道它的存储位置以便以后使用,有点像管道命令。

例如,这是通过 execve 执行命令“which”的程序集,本质上是执行命令“$ which ls”:

GLOBAL _start
SECTION .TEXT

_start:
    XOR         EAX,EAX
    PUSH        EAX
    PUSH        0x68636968 
    PUSH        0x772f6e69 
    PUSH        0x622f7273 
    PUSH        0x752f2f2f 
    MOV         EBX, ESP
    PUSH        EAX
    PUSH        0x736c
    MOV         ESI, ESP
    XOR         EDX, EDX
    PUSH        EDX
    PUSH        ESI
    PUSH        EBX
    MOV         ECX, ESP
    MOV         AL, 0x0B; EXECVE SYSCALL NUMBER
    INT         0x80

第 7-10 行将 /usr/bin/which 的地址压入堆栈,第 13 行将参数 ls 压入堆栈。然后它将参数数组压入堆栈并将其存储在 ECX 中,使 EBX 指向 /usr/bin/which 位置的地址,并将 EAX 设置为系统调用号 0xb (11) 用于 execve 系统调用。执行时,它返回 /bin/ls,即我们要求它查找的 ls 的位置。

我如何将 /bin/ls 的结果存储在某处以供其他用途?就像如果我想继续编写代码并将此处返回的内容用作下一段代码的一部分,我该如何将返回值保存在寄存器或堆栈中?

最佳答案

基本上,您必须对此做一些变体:

  1. 使用 pipe() 系统调用来创建一个 fifo。
  2. fork() 关闭子进程。在父进程中,这将返回您需要记住的子进程 ID。在 child 中,这返回零。
  3. 在父端关闭fifo的写端,在子端关闭读端。
  4. 在子进程中,使用dup2()将管道的写入端移动到文件描述符1。然后关闭管道的原始文件描述符。
  5. 在 child 中,execve 您要运行的程序。请注意,execve 用新图像替换了当前进程,因此我不确定您希望以前的程序如何工作。
  6. 在父级中,从管道读取直到遇到 EOF(即 read() 返回零)。你读到的是 child 的标准输出。将该输出存储在缓冲区中。
  7. 最后,使用wait() 收集到 child 的退出状态。如果不这样做,死去的 child 就会像僵尸一样在进程表中徘徊,占用资源。

除了管道,您还可以open() 一个文件来写入输出。这样做的好处是您可以使用 fstat() 找出进程写入了多少输出。但是,您随后需要实现类似于 tmpfile 函数的逻辑来创建和打开临时文件。

关于linux - 在汇编中执行后如何将 execve 系统调用的输出返回到寄存器或堆栈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44335313/

相关文章:

linux - 将 readbuffer 设置为 FBO 颜色附件失败并出现无效枚举错误

linux - 如何正确地将缓冲区指针传递给 x86_64 程序集中的 Linux 系统调用?

linux - 如何使用汇编语言从键盘读取输入字符串

c - Execv 的参数从第二个元素开始

linux - 测试命令和重定向 bash

linux - 用于检查文件中的路由器和接口(interface)列表上的 ATM 接口(interface)速度的 Bash 脚本

assembly - x86汇编两条目标相同的跳转指令

linux-kernel - linux系统调用实现

linux - 从扇区中的磁盘读取是原子的吗?

php - 守护一个 PHP 脚本,并提供终止它的选项