linux x86 tcp绑定shellcode(GAS语法)bind()不返回零

问题描述:

我想在linux x86架构上做一个tcp绑定shellcode,我使用GAS语法。 我可以成功调用socketcall(SYS_SOCKET),并得到一个文件描述符(这不是NULL) 现在即时通讯尝试使用该fd并进行SYS_BIND调用,我似乎从不是零的绑定返回值(它应该) 。我已经调试过它。一切都只是堆栈,但...linux x86 tcp绑定shellcode(GAS语法)bind()不返回零

这里是注释掉的代码:

.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 

编译:

as -ggstabs -o sys_socket.o sys_socket.s 

链接:

ld -o sys_socket sys_socket.o 

栈和之前注册最后的内核中断(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) 

那么问题出在哪里以及如何正确解决?

在此先感谢。

您将参数数组组装到堆栈上,但您需要传递要使用的系统调用的地址。你应该清理一下你的代码,这很难遵循你正在做的事情。作为一个快速黑客,movl %esp, %ecxint $0x80之前似乎工作,虽然不知道,如果你想这样的:

bind(3, {sa_family=AF_INET, sin_port=htons(44552), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 

还要注意的是jzjnz不比较eax0自动,那就是你不能直接使用它们在int $0x80之后。他们只是测试零标志。您必须添加代码才能根据您自己设置eax,如testl %eax, %eax

此外,你应该保持堆栈指针4字节对齐。 subl $30, %esp是一个非常糟糕的主意。


对于这个调用,你需要在内存中的2件事情。一个是参数数组。你需要传递一个指向ecx的指针。二,第二个参数本身必须是一个指向sockaddr结构的指针。

您在由esi+8指向的内存中构建sockaddr。你的评论不正确地说这是参数数组,但它不是。随后,通过堆栈上的3 push指令构建参数数组。因此参数数组的地址是esp,并且esp+4(第二个参数)的值指向esi+8,这是您的sockaddr。您错误地使用esi+8(前8个字节在那里未使用),但至少它是一致的,并且您有足够的内存分配,所以它恰好工作。

还要注意的是端口号预计将在网络(大尾数)字节顺序,这就是为什么你2222=0x08AE)将被解释为44552=0xAE08)。

+0

感谢您的意见。明白了关于jz和subl的观点。我将参数数组的地址加载到ecx中,并将它与SYS_BIND(2)一起传递给socketcall,然后调用中断。我已经将所有东西都推入堆栈,并将102推入eax,然后称为中断。在你说的时候没有得到你的观点:“你需要传递系统调用的地址才能使用。”你能否再解释一下。 – V1R4N64R

+0

更新了答案。 – Jester

+0

和yupp !!!谢谢你的很好的解释。现在我明白为什么它不起作用。我的意思是我应该把'esi + 24'和'leal 8(%esi),%ecx',然后'movl%ecx,28(%esi)'的文件描述符移到'esi + 24'的地址中进入'%ecx'等等...我将你的答案标记为解决方案。再次感谢您的分析和解释。亲切的问候... – V1R4N64R