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

问题描述 投票:0回答:2

我正在用汇编语言编写,我试图找出如何执行 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 设置为 execve 系统调用的系统调用号 0xb (11)。执行时,它返回
/bin/ls
,即我们要求它查找的
ls
的位置。

如何将

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

linux assembly system-calls shellcode execve
2个回答
0
投票

基本上,你必须做一些变化:

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

除了管道之外,您还可以

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


0
投票

我和约书亚·坎贝尔有同样的问题。

这里是一个用 nasm 编写的源代码示例的链接,它将使用 pipeline() 创建从父进程到子进程的管道并运行外部命令 (

/bin/echo 'Hello World'
),将结果复制到缓冲区中[tmp] 并随后显示/打印结果:

https://gitlab.com/pagaco/nasm-examples-pipe-linux-64bit/-/blob/main/pipe3/pipe3.asm

程序的具体顺序可以在源代码中找到。 此源代码示例适用于 64 位 Linux 操作系统。

也许这对你有帮助。

致以诚挚的问候。

© www.soinside.com 2019 - 2024. All rights reserved.