Why syscall doesn't work?

若如初见. 提交于 2021-02-05 07:11:07

问题


I'm on MAC OSX and I'm trying to call through assembly the execve syscall.. His opcode is 59 . In linux I have to set opcode into eax, then parameters into the others registers, but here I have to put the opcode into eax and push parameters into the stack from right to left.

So I need execve("/bin/sh",NULL,NULL), I found somewhere that with assembly null=0, so I put null into 2nd and 3rd parameters.

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

When I try to execute it say: Bad system call: 12


回答1:


32-bit programs on BSD (on which OS/X is based) requires you to push an extra 4 bytes onto the stack if you intend to call int 0x80 directly. From the FreeBSD documentation you will find this:

By default, the FreeBSD kernel uses the C calling convention. Further, although the kernel is accessed using int 80h, it is assumed the program will call a function that issues int 80h, rather than issuing int 80h directly.

[snip]

But assembly language programmers like to shave off cycles. The above example requires a call/ret combination. We can eliminate it by pushing an extra dword:

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

When calling int 0x80 you need to adjust the stack pointer by 4. Pushing any value will achieve this. In the example they just do a push eax. Before your calls to int 0x80 push 4 bytes onto the stack.

Your other problem is that add eax,0x3b for example requires EAX to already be zero which is almost likely not the case. To fix that add an xor eax, eax to the code.

The fixes could look something like:

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

Your code is actually called the JMP/CALL/POP method and is used for writing exploits. Are you writing an exploit or did you just find this code online? If it is intended to be used as shell code you would need to avoid putting a 0x00 byte in the output string. push 0x00 will encode 0x00 bytes in the generated code. To avoid this we can use EAX which we are now zeroing out and push it on the stack. As well you won't be able to NUL terminate the string so you'd have to move a NUL(0) character into the string. One way after zeroing EAX and popping EBX is to move zero to the end of the string manually with something like mov [ebx+7], al. Seven is the index after the end of the string /bin/sh. Your code would then look like this:

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



回答2:


You are using a 64 bit syscall numbers and a 32 bit instruction to jump to the syscall. That is not going to work.

For 32 bit users:

opcode for Linux/MacOS execve: 11
instruction to call syscall: int 0x80

For 64 bit users:

opcode for Linux execve: 59 (MacOS 64-bit system calls also have a high bit set).
instruction to call syscall: syscall

The method for passing args to system calls is also different: 32-bit uses the stack, 64-bit uses similar registers to the function-calling convention.



来源:https://stackoverflow.com/questions/43440535/why-syscall-doesnt-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!