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

Gni*_*ohz 6 c assembly shellcode

我正在尝试编写一个运行execve的shellcode.等效的c程序如下所示:

int main ()
{

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

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

c程序运行正常.然后我尝试编写我的测试程序(修改为推送null):

#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"
    );
    }
Run Code Online (Sandbox Code Playgroud)

我在这里有内存中字符串的地址,我们可以假设它们不会改变.但是我们没有字符串'-i'的地址.所以我在这里做的是将参数推送到堆栈中,如下所示:


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

|addressof"/bin/sh"(rsi points to here)|addressof"-i"|addressof"/dev/ssh"|addressof"/bin/sh"(rdi points to here)|-i|
Run Code Online (Sandbox Code Playgroud)

它没用.程序编译正常但是当我运行该程序时,没有任何反应.

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

编辑

感谢Niklas B的以下建议,我使用了trace来查看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).只有当地址是字符串时,这非常接近正确答案...

感谢Brian,我现在看到问题出在哪里.硬编码地址位于另一个程序的共享库中.因此,该程序在实际输入该程序之前不应运行.谢谢大家,我会尽快更新.如果问题解决了,我会将其标记为已解决.

Bri*_*ell 3

正如 Kerrek SB 和 user9000 在注释中指出的那样,该argv数组必须是一个以 null 结尾的字符串数组。

一旦修复了这个问题,独立运行该程序仍然无法工作,因为字符串"/bin/sh""/dev/tty"可能不存在于您刚刚编译的程序中的该位置,而是存在于 shell 代码所在的程序中的该位置旨在瞄准。您需要将其实际注入到该程序中,以便它将在那里执行,这些字符串位于这些地址处。