i'm trying to make a tcp bind shellcode on linux x86 architecture and i'm using GAS syntax. i could successfully call socketcall(SYS_SOCKET) and got a file descriptor (which is not NULL) now that im trying to use that fd and make a SYS_BIND call i seem to get a return value from bind which is not ZERO (which it should be) . i've already debugged it . everything is just on the stack but ...
here is the commented code :
.text
.globl _start
_start:
    xorl %eax, %eax
    xorl %ebx, %ebx
    movb $1, %bl
    subl $30, %esp
    movl %esp, %esi
# array of arguments for socketcall->SYS_SOCKET:
    movb $2, 8(%esi)
    movb $1, 12(%esi)
    movl %eax, 16(%esi)
# load the address of that array in ecx:
    leal 8(%esi), %ecx
    movb $102, %al
    int $0x80
    jz exit0 # exit(0) if eax(return value)==0
# ---------------------------------------------------------------------
bind:
    movl %eax, %edx       # save the file descriptor
    xorl %eax, %eax
    inc %bl               # bl == 2 -> bind
    movw $2, 8(%esi)      # sa_family == AF_INET
    movw $2222, 10(%esi)  # sin_port == 2222
    movl %eax, 12(%esi)   # INADDR_ANY
    movl %eax, 16(%esi)   # sin_zero
    movl %eax, 20(%esi)   # sin_zero
    addl $16, %eax        
    pushl %eax            # size of struct sockaddr(16) as the third argument of bind,pushed first
    leal 8(%esi), %ecx    # leal the address of argument array into ecx
    pushl %ecx            # push it onto the stack
    pushl %edx            # file descriptor (first argument)
    movb $102, %al        # socketcall
    int $0x80
    jnz exit1 # exit(1) if bind() return value is not zero (zero flag is not set)
# ---------------------------------------------------------------------------
exit0:
    xorl %eax, %eax
    inc %eax
    xorl %ebx, %ebx
    int $0x80
# --------------------------------------------------------------------------
exit1:
    xorl %eax, %eax
    inc %eax
    xorl %ebx, %ebx
    inc %ebx
    int $0x80 
compiled:
as -ggstabs -o sys_socket.o sys_socket.s
linked:
ld -o sys_socket sys_socket.o
STACK and Registers just before the last kernel interrupt (GDB) :
(gdb) x/8xw $esp
0xbffff5d6: 0x00000007  0xbffff5ea  0x00000010  0x00000000
0xbffff5e6: 0x00000000  0x08ae0002  0x00000000  0x00000000
(gdb) x/1xb 0xbffff5ea
0xbffff5ea: 0x02
(gdb) i r
eax            0xfffffff7   -9
ecx            0xbffff5ea   -1073744406
edx            0x7  7
ebx            0x2  2
esp            0xbffff5d6   0xbffff5d6
ebp            0x0  0x0
esi            0xbffff5e2   -1073744414
edi            0x0  0
eip            0x8048099    0x8048099 <bind+40>
eflags         0x202    [ IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x0  0
(gdb) 
so where is the problem and how to solve it exactly ?
thanks in advance.
 V1R4N64R
 V1R4N64RYou assemble the argument array on the stack, but you need to pass the address for the system call to use. You should clean up your code a little, it's hard to follow what you are doing. As a quick hack, movl %esp, %ecx before int $0x80 seems to work, although not sure if you wanted this:
bind(3, {sa_family=AF_INET, sin_port=htons(44552), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
Also note that jz and jnz do not compare eax to 0 automatically, that is you can't use them directly after int $0x80. They just test the zero flag. You have to add code to set it based on eax yourself, such as testl %eax, %eax.
Furthermore, you should really keep the stack pointer 4 bytes aligned. subl $30, %esp is a very bad idea.
For this call, you need 2 things in memory. One, the argument array. You need to pass a pointer to that in ecx. Two, the second argument itself has to be a pointer to a sockaddr struct.
You build the sockaddr in memory pointed to by esi+8. Your comment incorrectly says that's the argument array, but it isn't. You build the argument array by the 3 push instructions on the stack, subsequently. As such the address of the argument array is esp, and the value at esp+4 (the second argument) points to esi+8 which is your sockaddr. You misleadingly use esi+8 (the first 8 bytes are unused there), but at least it's consistent and you have enough memory allocated, so it happens to work.
Also note that the port number is expected to be in network (big endian) byte order, that's why your 2222 (=0x08AE) will be interpreted as 44552 (=0xAE08).
User contributions licensed under CC BY-SA 3.0