2012-08-08 72 views
0

我在Ubuntu 11.10的x86写的shellcode和INT 0x80的系统调用之前,寄存器是这样的:基本的Shellcode的connect()函数

eax 0x66 
    ecx 0x8e60558 
    edx 0x0 
    ebx 0x3 

其设置为connect()系统调用。在ECX寄存器中的值是一个参数阵列,其中包含:

0x8e60558: 0x00000009 0x8e60583 0x00000010 

其中0x00000009是文件描述符,0x8e60583是服务器结构指针指向:

0x8e60583: 0x00000002 0x0000115c 0x7f000001 

它是:

[address]: [AF_INET=2] [PORT=4444] [IP=127.0.0.1] 

我知道该文件描述是正确的,所有的寄存器设置像EAX存储0x66的常数值(socketcall是系统调用#102)是正确的,据我所知然而,当我运行的代码,它应该在EAX寄存器返回连接插座FD,它返回:

eax: 0xffffff9b 

这显然是错误的。我有我做错了吗?

编辑:inet_address的更改字节序。

+0

返回代码是给错误代码负数。它说什么? – BjoernD 2012-08-08 07:56:02

+0

为了完整起见,你可能想补充说'0xffffff9b'是'-101'的二进制补码,它恰好是Linux上的'ENETUNREACH'(网络无法访问)的值。 – Giel 2012-08-08 08:05:39

+0

^谢谢你的补充。我也忘了提到这台Ubuntu机器是在虚拟机中运行的,只使用一台主机专用适配器,但考虑到127.0.0.1仍然有效,这应该不是问题吗?... – 2012-08-08 08:11:54

回答

1

你的问题是,你是编码参数的connect系统调用的小尾数,而他们中的一些应该是大端,另外两个sin_family和sin_port成员被编码为32位,他们应该是16位和该结构似乎需要填充到16个字节。

PS您可能需要使用汇编,你可以随时使用objdump -x -D $binary来获得操作码。此外,我与gcc -c -x assembler-with-cpp -o hello-net.o hello-net.S && ld -o hello-net hello-net.o编译,以便能够使用预处理器为好。

PS2:你可能想尝试执行你的代码strace,它显示你正在做的实际系统调用。

E.g.这个测试程序对我的作品(x86_64的):

#include <asm/unistd.h> 

#define AF_INET   2 
#define SOCK_STREAM  1 

hellostr: 
    .ascii "Hello world!\n"   # 'Hello world!' plus a linefeed character 
.equ helloLen, . - hellostr    # Length of the 'Hello world!' string 

.align 8 
home_addr: 
    # AF_INET (native-endian) 
    .short AF_INET 
    # big-endian port 4444 
    .byte 0x11, 0x5c 
    # big-endian 127.0.0.1 
    .byte 0x7f, 0x00, 0x00, 0x01 
    # required padding to 16 bytes 
    .space 16 - (. - home_addr) 
.equ home_len, . - home_addr 

.globl _start 
_start: 
    # syscall(SYS_socket, AF_INET, SOCK_STREAM, 0) 
    mov $__NR_socket, %rax 
    mov $AF_INET, %rdi 
    mov $SOCK_STREAM, %rsi 
    mov $0, %rdx 
    syscall 

    # syscall(SYS_connect, socket, [127.0.0.1:4444], sizeof(addr)) 
    mov %rax, %rdi 
    mov $__NR_connect, %rax 
    mov $home_addr, %rsi 
    mov $home_len, %rdx 
    syscall 

    # syscall(SYS_write, socket, hellostr, strlen(hellostr)) 
    mov $__NR_write, %rax 
    mov $hellostr, %rsi # Put the offset of hello in ecx 
    mov $helloLen, %rdx # helloLen is a constant, so we don't need to say 
         # mov edx,[helloLen] to get it's actual value 
    syscall    # Call the kernel (syscall num in %rax) 

    mov $__NR_exit, %rax 
    xor %rdi, %rdi  # Exit with return code of 0 (no error) 
    syscall 

同样的事情,但修改,以得到它在x86工作(32位):

#include <asm/unistd.h> 

#define AF_INET   2 
#define SOCK_STREAM  1 

#define SYS_SOCKET 1  /* sys_socket(2)  */ 
#define SYS_CONNECT 3  /* sys_connect(2)  */ 

hellostr: 
    .ascii "Hello world!\n"   # 'Hello world!' plus a linefeed character 
.equ helloLen, . - hellostr    # Length of the 'Hello world!' string 

.align 8 
home_addr: 
    # AF_INET (native-endian) 
    .short AF_INET 
    # big-endian port 4444 
    .byte 0x11, 0x5c 
    # big-endian 127.0.0.1 
    .byte 0x7f, 0x00, 0x00, 0x01 
    # required padding to 16 bytes 
    .space 16 - (. - home_addr) 
.equ home_len, . - home_addr 

.align 8 
sys_socket_args: 
    .int AF_INET 
    .int SOCK_STREAM 
    .int 0 

.globl _start 
_start: 
    # syscall(SYS_socketcall, SYS_SOCKET, {AF_INET, SOCK_STREAM, 0}) 
    mov $__NR_socketcall, %eax 
    mov $SYS_SOCKET, %ebx 
    mov $sys_socket_args, %ecx 
    int $0x80 

    # syscall(SYS_socketcall, SYS_CONNECT, {socket, [127.0.0.1:4444], sizeof(addr)}) 

    # Allocate 12 bytes of stack space (required for arguments to connect(2)) 
    sub $12, %esp 

    mov %eax, (%esp)   # sys_connect_args.fd  = return-value 
    movl $home_addr, 4(%esp) # sys_connect_args.addr = &home_addr 
    movl $home_len, 8(%esp) # sys_connect_args.addrlen = sizeof(home_addr) 
    mov $__NR_socketcall, %eax 
    mov $SYS_CONNECT, %ebx 
    mov %esp, %ecx 
    int $0x80 

    # syscall(SYS_write, socket, hellostr, strlen(hellostr)) 
    mov $__NR_write, %eax 
    mov (%esp), %ebx # socket-param = sys_connect_args.fd 
    mov $hellostr, %ecx # Put the offset of hello in ecx 
    mov $helloLen, %edx # helloLen is a constant, so we don't need to say 
         # mov edx,[helloLen] to get it's actual value 
    int $0x80   # Call the kernel (syscall num in %eax) 

    # restore stack 
    add $12, %esp 

    mov $__NR_exit, %eax 
    xor %ebx, %ebx  # Exit with return code of 0 (no error) 
    int $0x80 

编辑:扩展第一段提及另外两个可能的错误,并添加一个适用于我的32位(x86)样本。

+0

改变了它,但我仍然得到相同的错误。 – 2012-08-08 09:35:09