Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C Linux x86_64汇编套接字编程_C_Linux_Sockets_Assembly_X86 64 - Fatal编程技术网

C Linux x86_64汇编套接字编程

C Linux x86_64汇编套接字编程,c,linux,sockets,assembly,x86-64,C,Linux,Sockets,Assembly,X86 64,大家好。 因此,我正在学习汇编。按照我学习的任何新语言的常规学习步骤,我已经与汇编建立了联系 遗憾的是,这并不顺利,因为我在第0步几乎失败了,这将获得一个可以开始通信的套接字 汇编代码应大致等于以下C代码: #include <stdio.h> #include <sys/socket.h> int main(){ int sock; sock = socket(AF_INET, SOCK_STREAM, 0); } #包括 #包括 i

大家好。

因此,我正在学习汇编。
按照我学习的任何新语言的常规学习步骤,我已经与汇编建立了联系

遗憾的是,这并不顺利,因为我在第0步几乎失败了,这将获得一个可以开始通信的套接字

汇编代码应大致等于以下C代码:

#include <stdio.h>
#include <sys/socket.h>

int main(){
        int sock;
        sock = socket(AF_INET, SOCK_STREAM, 0);
}
#包括
#包括
int main(){
int袜子;
sock=socket(AF\u INET,sock\u STREAM,0);
}
(让我们忽略一个事实,即它现在还没有关闭套接字。)

以下是我迄今为止所做的:

  • 检查过了。这意味着我需要做一个
    socketcall()
    这一切都很好。问题开始于它需要一个
    int
    来描述它应该进行什么样的socketcall。这些电话也没有多大帮助,因为它只描述了:
在某些体系结构上,例如x86-64和ARM,没有 socketcall()系统调用;而是套接字(2)、接受(2)、绑定(2)和 因此,它们实际上是作为单独的系统调用实现的

  • 然而,在最初的系统调用列表中没有这样的调用——据我所知,
    socket()
    accept()
    bind()
    listen()
    ,等等都是来自
    libnet
    的调用,而不是来自内核的调用。这让我完全困惑,所以我决定编译上面的
    C
    代码,并用
    strace
    检查它。这产生了以下结果:

    套接字(PF_INET、SOCK_STREAM、IPPROTO_IP)=3

  • 虽然这并没有让我更进一步地了解什么是
    socket()
    ,但它确实解释了它的参数。对于witch,我似乎没有找到合适的文档(再次)。我原以为
    PF\u INET
    SOCK\u STREAM
    IPPROTO\u IP
    将在
    中定义,但我的
    grep
    -ing对它们似乎没有任何用处。所以我决定使用
    gdb
    disassmain
    来查找值。这产生了以下输出:

    主功能的汇编程序代码转储: 0x00000000004004fd:推送rbp 0x00000000004004fe:mov rbp,rsp 0x0000000000400501:子rsp,0x10 0x0000000000400505:mov edx,0x0 0x000000000040050a:mov esi,0x1 0x000000000040050f:mov edi,0x2 0x0000000000400514:调用0x400400 0x0000000000400519:mov DWORD PTR[rbp-0x4],eax 0x000000000040051c:离开
    0x000000000040051d:ret
    汇编程序转储结束

  • 根据我的经验,这意味着
    socket()
    EDX
    PF_INET
    )、
    ESI
    SOCK_STREAM
    )和
    EDI
    IPPROTO_IP
    )获取其参数。这对于系统调用来说是很奇怪的(linux系统调用的惯例是使用
    EAX
    /
    RAX
    作为调用号,并使用其他寄存器作为参数的递增顺序,例如
    RBX
    RCX
    RDX
    …)。这是being
    CALL
    -ed而不是
    int0x80
    'd这一事实也意味着这实际上不是一个系统调用,而是从共享对象调用的东西。或者别的什么

  • 但话说回来。对于
    调用
    -ed的对象,在寄存器中传递参数是非常奇怪的。通常,据我所知,被调用对象的参数应该是
    推到堆栈上,因为编译器不知道他们将尝试使用哪些寄存器

  • 当使用
    ldd
    检查生成的二进制文件时,这种行为变得更加奇怪:

    linux vdso.so.1(0x00007fff4a7fc000) libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007f56b0c61000) /lib64/ld-linux-x86-64.so.2(0x00007f56b1037000)

  • 似乎没有网络库的链接

这就是我失去创意的地方

因此,我提出以下要求:

  • 描述
    x86-64
    linux内核的实际系统调用及其相关编号的文档。(最好作为
    C
    的头文件)
  • 定义
    PF_INET
    SOCK_STREAM
    IPPROTO_IP
    的头文件,因为我在自己的系统上找不到它们,这让我非常恼火
  • 也许是关于在
    x86-64
    linux上汇编网络的教程。(对于
    x86-32
    很容易找到材料,但出于某种原因,我的64位内容是空的。)

谢谢

64位调用约定确实使用寄存器在用户空间和系统调用中传递参数。如您所见,用户空间约定是
rdi
rsi
rdx
rcx
r8
r9
。对于系统调用,使用
r10
代替被syscall指令阻塞的
rcx
。有关更多详细信息,请参阅或ABI文档

各种常量的定义隐藏在头文件中,但如果您安装了必要的开发包,则可以通过文件系统搜索轻松找到头文件。您应该查看
/usr/include/x86\u 64-linux-gnu/bits/socket.h
/usr/include/linux/in.h

至于系统调用列表,它对于googleone来说是微不足道的,比如。当然,您也可以随时查看内核源代码

socket.asm

);插座

);使用:nasm-f elf socket.asm编译

);链接(64位系统需要elf_i386选项):ld-m elf_i386 socket.o-o socket

);使用:./socket运行

%包括“functions.asm”

第节.案文 全球启动

_开始:

xor     eax, eax            ; init eax 0
xor     ebx, ebx            ; init ebx 0
xor     edi, edi            ; init edi 0
xor     esi, esi            ; init esi 0
_插座:

push    byte 6              ; push 6 onto the stack (IPPROTO_TCP)
push    byte 1              ; push 1 onto the stack (SOCK_STREAM)
push    byte 2              ; push 2 onto the stack (PF_INET)
mov     ecx, esp            ; move address of arguments into ecx
mov     ebx, 1              ; invoke subroutine SOCKET (1)
mov     eax, 102            ; invoke SYS_SOCKETCALL (kernel opcode 102)
int     80h                 ; call the kernel

call    iprintLF            ; call our integer printing function (print the file descriptor in EAX or -1 on error)
_出口:

call    quit                ; call our quit function

这是针对x86系统的。如果您想使用x86_64系统
[bits 32]

global _start
section .data
   msg: db "Socket Failed To Create!",0xa,0
   len: equ $-msg

   msg1: db "Socket Created",0xa,0
   len1: equ $-msg1

   msg2: db "Recv Or Send Failed",0xa,0
   len2: equ $-msg2

   msg3: db "Shutdown Socket Failed",0xa,0
   len3: equ $-msg3

   DATASIZE:        equ 5

   SOCK_STREAM:     equ 1
   AF_INET:         equ 2
   AF_INET:         equ 2
   INADDR_ANY:      equ 0
   MSG_WAITALL:     equ 0x100
   MSG_DONTWAIT:    equ 0x40
   SHUT_RDWR:       equ 2

    SYS_SOCKET:     equ 1       ; sys_socket(2)
    SYS_BIND:       equ 2       ; sys_bind(2)
    SYS_CONNECT:    equ 3       ; sys_connect(2)
    SYS_LISTEN:     equ 4       ; sys_listen(2)
    SYS_ACCEPT:     equ 5       ; sys_accept(2)
    SYS_GETSOCKNAME:equ 6       ; sys_getsockname(2)
    SYS_GETPEERNAME:equ 7       ; sys_getpeername(2)
    SYS_SOCKETPAIR: equ 8       ; sys_socketpair(2)
    SYS_SEND:       equ 9       ; sys_send(2)
    SYS_RECV:       equ 10      ; sys_recv(2)
    SYS_SENDTO:     equ 11      ; sys_sendto(2)
    SYS_RECVFROM:   equ 12      ; sys_recvfrom(2)
    SYS_SHUTDOWN:   equ 13      ; sys_shutdown(2)
    SYS_SETSOCKOPT: equ 14      ; sys_setsockopt(2)
    SYS_GETSOCKOPT: equ 15      ; sys_getsockopt(2)
    SYS_SENDMSG:    equ 16      ; sys_sendmsg(2)
    SYS_RECVMSG:    equ 17      ; sys_recvmsg(2)
    SYS_ACCEPT4:    equ 18      ; sys_accept4(2)
    SYS_RECVMMSG:   equ 19      ; sys_recvmmsg(2)
    SYS_SENDMMSG:   equ 20      ; sys_sendmmsg(2)

struc sockaddr_in, -0x30
    .sin_family:    resb 2  ;2bytes
    .sin_port:      resb 2  ;2bytes
    .sin_addr:      resb 4  ;4bytes
    .sin_zero:      resb 8  ;8bytes
endstruc

struc socket, -0x40
    .socketfd       resb 4
    .connectionfd   resb 4
    .count          resb 4
    .data           resb DATASIZE
endstruc

section .text

_start:
    push ebp
    mov ebp, esp
    sub esp, 0x400 ;1024byte

    xor edx, edx    ;or use cdq
    ;
    ; int socket(int domain, int type, int protocol);
    ; domain: The domain argument specifies a communication domain
    ; 
    push edx                        ; Push protocol
    push dword SOCK_STREAM          ; Push type
    push dword AF_INET              ; Push domain
    mov ecx, esp                    ; ECX points to args
    mov ebx, SYS_SOCKET             ;
    mov eax, 0x66                   ; socketcall()
    int 0x80

    cmp eax, 0
    jl .socket_failed
    mov [ebp + socket.socketfd], eax

    ;
    ; fill struct sockaddr_in serv_addr;
    ;
    mov word [ebp + sockaddr_in.sin_family], AF_INET
    mov word [ebp + sockaddr_in.sin_port], 0x3905
    mov dword [ebp + sockaddr_in.sin_addr], INADDR_ANY

    push dword [ebp + sockaddr_in.sin_addr]
    push word  [ebp + sockaddr_in.sin_port]
    push word  [ebp + sockaddr_in.sin_family]

    mov ecx, esp

    ;
    ; int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    ;
    push byte 0x10                  ; sizeof(struct sockaddr)
    push ecx                        ; pointer struct sockaddr
    push dword [ebp + socket.socketfd]
    mov ecx, esp                    ; ECX points to args
    mov ebx, SYS_BIND               ;
    mov eax, 0x66
    int 0x80

    cmp eax, 0
    jne .socket_failed


    ;
    ;   int listen(int sockfd, int backlog);
    ;
    push dword 0x10
    push dword [ebp + socket.socketfd]
    mov ecx, esp
    mov ebx, SYS_LISTEN
    mov eax, 0x66
    int 0x80
    cmp eax, 0
    jne .socket_failed



    ;
    ; int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    ;
    xor ebx, ebx
    push ebx
    push ebx
    push dword [ebp + socket.socketfd]
    mov ecx, esp
    mov ebx, SYS_ACCEPT
    mov eax, 0x66
    int 0x80
    cmp eax, -1
    je .socket_failed
    mov [ebp + socket.connectionfd], eax

    mov dword [ebp + socket.count], 0
.again:
    lea edi, [ebp + socket.data]
    mov ecx, DATASIZE
    mov eax, 0
    rep stosd

    lea eax, [ebp + socket.data]
    ;
    ; ssize_t recv(int sockfd, const void *buf, size_t len, int flags);
    ;
    push dword MSG_WAITALL
    push dword DATASIZE
    push eax
    push dword [ebp + socket.connectionfd]
    mov ecx, esp
    mov ebx, SYS_RECV
    mov eax, 0x66
    int 0x80
    cmp eax, 0
    jle .recv_or_send_failed

    mov edx, eax
    lea ecx, [ebp + socket.data]
    call printk

    inc dword [ebp + socket.count]
    cmp dword [ebp + socket.count], 5
    jle  .again
.break:
    ;
    ; int shutdown(int sockfd, int how);
    ;
    push dword SHUT_RDWR
    push dword [ebp + socket.socketfd]
    mov ecx, esp
    mov ebx, SYS_SHUTDOWN
    mov eax, 0x66
    int 0x80
    cmp eax, 0
    jne .shutdown_failed

    ;
    ; int close(int fd)
    ;
    mov ebx, [ebp + socket.connectionfd]
    mov eax, 0x06
    int 0x80
    cmp eax, 0
    jne .shutdown_failed

    jmp .success

.shutdown_failed:
    mov edx, len3
    mov ecx, msg3
    call printk
    jmp .end
.recv_or_send_failed:
    mov edx, len2
    mov ecx, msg2
    call printk
    jmp .end
.socket_failed:

    mov edx, len
    mov ecx, msg
    call printk
    jmp .end

.success:
    mov edx, len1
    mov ecx, msg1
    call printk
    jmp .end
.end:
   leave

   mov     ebx,0               ;first syscall argument: exit code
   mov     eax,1               ;system call number (sys_exit)
   int     0x80                ;call kernel

   ret

   
; EDX: message length
; ECX: pointer to message to write
printk:
    pusha
    mov     ebx,1               ;first argument: file handle (stdout)
    mov     eax,4               ;system call number (sys_write)
    int     0x80                ;call kernel
    popa
    ret