你的问题是,你是编码参数的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)样本。
返回代码是给错误代码负数。它说什么? – BjoernD 2012-08-08 07:56:02
为了完整起见,你可能想补充说'0xffffff9b'是'-101'的二进制补码,它恰好是Linux上的'ENETUNREACH'(网络无法访问)的值。 – Giel 2012-08-08 08:05:39
^谢谢你的补充。我也忘了提到这台Ubuntu机器是在虚拟机中运行的,只使用一台主机专用适配器,但考虑到127.0.0.1仍然有效,这应该不是问题吗?... – 2012-08-08 08:11:54