【问题标题】:ARM, GNU assembler: how to pass "array" arguments to execve()?ARM,GNU 汇编器:如何将“数组”参数传递给 execve()?
【发布时间】:2015-05-25 10:47:10
【问题描述】:

我正在编写一个简单的 shellcode,它会为 ARM 平台(Raspberry PI 上的 Linux)调用 execve(),但遇到了 execve 的第二个参数。根据documentation

int execve(const char *filename, char *const argv[], char *const envp[]);

如果我打电话给execve("/bin/sh", {NULL}, {NULL});(从大会的角度来看),这对我来说完全不合适:

.data

.section .rodata

.command:
        .string "/bin/sh"

.text

.globl _start

_start: 
        mov r7, #11
        ldr r0, =.command
        eor r1, r1 @ temporarily forget about argv
        eor r2, r2 @ don't mind envp too
        svc #0

        mov r7, #1
        eor r0, r0
        svc #0

上面的程序集编译得很好,并在我的测试机器上运行时调用了一个 shell,它具有真正的/bin/sh。然而,我所有的麻烦是在特定的目标框本身没有/bin/sh,而只有一个指向busybox的符号链接,这需要我执行execve("/bin/busybox", {"/bin/busybox", "sh", NULL}, {NULL})之类的东西。

据我所知,数组在内存中是连续的,所以我所要做的就是以连续的方式在内存中分配字节,然后将指针指向我认为是这样的“数组”的开头。考虑到这一点,我尝试了以下操作:

.data

.section .rodata

.command:
        .string "/bin/busybox"

.args:  
        .ascii "/bin/busybox\0"
        .ascii "sh\0"
        .ascii "\0"

.text

.globl _start

_start: 
        mov r7, #11
        ldr r0, =.command
        ldr r1, =.args
        eor r2, r2
        svc #0

        mov r7, #1
        eor r0, r0
        svc #0

但是没有成功。试图玩弄字节并创建一系列填充空字节以对齐到 4 个字节的字节,这也不起作用。如果.args 标签如下所示:

.args:  
        .ascii "/bin/sh\0"
        .ascii "-c\0\0\0"
        .ascii "ls\0\0\0"
        .ascii "\0\0\0\0"

那么strace正在执行的程序如下:

$ strace ./shell
execve("./shell", ["./shell"], [/* 19 vars */]) = 0
dup2(0, 4)                              = 4
dup2(1, 4)                              = 4
dup2(2, 4)                              = 4
execve("/bin/sh", [0x6e69622f, 0x68732f, 0x632d, 0x736c00], [/* 0 vars */]) = -1 EFAULT (Bad address)
exit(0)                                 = ?
+++ exited with 0 +++

(尝试先在测试机上执行/bin/sh -c ls,然后再编码/bin/busybox sh)。

我运行了一个类似的 C 程序,然后对其进行调试,看看它是如何完成的。似乎传递给r1 的位置包含一堆指向字符串的指针,然后自然是0x00:

(gdb) x/4xw 0xbefff764
0xbefff764:     0x000105d0      0x000105d8      0x000105dc      0x00000000

... snip ...

(gdb) p argv
$3 = {0x105d0 "/bin/sh", 0x105d8 "-c", 0x105dc "ls", 0x0}

问题 既然我弄清楚了内存是如何布局的,那么如何在汇编中准备这样的布局并正确地将第二个参数作为 ARM 汇编语言中的“数组”传递给execve()

【问题讨论】:

  • 标记每个参数并创建这些标签的数组并将地址传递给它。这就是 C 字符串数组的工作原理(char** 类型)。
  • @Jester 这就是我刚刚意识到我可以通过查看一些来源在汇编中做的事情。谢谢。

标签: linux assembly arm shellcode execve


【解决方案1】:

天哪,我刚想出这个...几个小时的摆弄,然后在发布我自己的问题 2 分钟后,我得到了答案...橡皮鸭调试工作。

.data

.section .rodata

command:
        .string "/bin/sh"

arg0:  
        .string "/bin/sh"

arg1:  
        .string "-c"

arg2:  
        .string "ls"

args:  
        .word arg0
        .word arg1
        .word arg2
        .word 0

.text

.globl _start

_start: 
        mov r7, #11
        ldr r0, =command
        ldr r1, =args
        eor r2, r2
        svc #0

        mov r7, #1
        eor r0, r0
        svc #0

【讨论】:

  • .ascii "\0\0\0\0" 是一种有趣的说法.word 0 :) 此外,使用以点开头的符号 (.) 也不是一个好主意,因为它们可能与指令混淆。
  • @Jester 是的,在摆弄某些东西时代码是一团糟,所以最初它只是我检查内存的一个标记,然后我添加了零。稍后我会复习一下。
  • 对于 C 字符串,您可能还会发现 .asciz 指令比手动终止所有内容更方便。
  • @Notlikethat 我忙于 shellcode 并且对原始字节特别感兴趣,所以我明确声明了空字节。无论如何,在调整 shellcode 时必须摆脱那些。我想上面的程序集只是为了更好地解释我的问题。我的本地版本与上述版本相差甚远(=
  • 如果我想执行调用程序的参数怎么办?
【解决方案2】:

您可以使用堆栈指针来传递参数。程序启动时,第一个参数(arg[1])会在sp+8中。

shell.s:

    .text
    .globl _start
    _start: 
        .code 32
            add r3,pc,#1
            bx r3
        .code 16
            ldr r0, [sp, #8] @ load argv[1] to r0
            add r1, sp, #8   @ set &argv[1] to r1
            eor r2, r2       @ set NULL to r2
            mov r7, #11
            svc #1

此代码与下一个 c 代码相同:

#include <unistd.h>

int main(int argc, char *argv[])
{
    execve(argv[1], &argv[1], NULL);
    return 0;
}

第三个参数是envp,可以设置为NULL。

启动 /bin/sh:

shell /bin/sh

我希望这对某人有所帮助

【讨论】:

  • 对于未来的读者,eor r2, r2 只是在 shellcode 中避免机器代码中出现0 字节的好主意。与 x86 不同,将寄存器归零的有效方法是 mov r2, #0。 (以防万一有人想知道这在 ARM 上是否是一个好主意:它不是。)
  • 如果您评论了代码,这将是一个更好的答案,例如ldr 正在加载 argv[1],一个指向 "/bin/sh" 的指针。 r1 得到一个指向整个 argv[] 数组的指针。并且Linux支持envp=NULLenvp=指向NULL的指针相同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-16
  • 2016-12-08
  • 1970-01-01
  • 2022-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多