0

我正在 Ubuntu 11.10 x86 上编写 shellcode,int 0x80 系统调用之前的寄存器如下所示:

    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]

我知道文件描述符是正确的,并且在寄存器中设置的所有常量值(例如将 0x66 存储在 eax 中(socketcall 是 syscall #102)据我所知是正确的,但是当我运行代码时,它应该返回在 eax 寄存器中连接套接字 FD,它返回:

    eax: 0xffffff9b

这显然是错误的。我做错了什么?

编辑:更改 inet_address 的字节序。

4

1 回答 1

2

您的问题是您将连接系统调用的参数编码为小端,而其中一些应该是大端,此外 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,它显示了您正在进行的实际系统调用。

例如,这个测试程序适用于我(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) 示例。

于 2012-08-08T08:33:53.920 回答