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.
You 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