0

Ubuntu 11.10 x86 でシェルコードを書いていますが、int 0x80 syscall の前のレジスタは次のようになります。

    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) に格納するなどのレジスタに設定されたすべての定数値は、コードを実行すると、私の知る限りでは正しいことを知っています。接続されたソケット FD を eax レジスタに格納すると、次のように返されます。

    eax: 0xffffff9b

これは明らかに間違っています。私が間違ったことをしましたか?

編集: inet_address のエンディアンを変更しました。

4

1 に答える 1

2

あなたの問題は、connect syscall へのパラメーターをリトル エンディアンとしてエンコードしている一方で、それらの一部はビッグ エンディアンである必要があることです。さらに、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

編集:最初の段落を拡張して、他の2つの考えられるエラーに言及し、私にとって機能する32ビット(x86)のサンプルを追加しました。

于 2012-08-08T08:33:53.920 に答える