FASM编写的ELF64 Socket程序Nmap无法检测指定IP问题求助
ELF64 Socket程序绑定失败问题排查与修复
我用FASM编写了ELF64架构的Socket程序,绑定IP为192.168.0.17,但Nmap无法检测到该端口。尝试过小端序处理仍无效,怀疑问题出在地址或端口配置上。代码参考Chromium OS编写,使用syscall而非32位int 0x80指令,原始代码如下:
format ELF64 section '.data' IPPROTO_TCP equ 0x06 SOCK_STREAM equ 0x01 AF_INET equ 0x02 message db 'welcome',0xA,0 message_lenght = $-message struc sockaddr sin_family,sin_port,sin_addr { .sin_family dw sin_family .sin_port dw sin_port; 1461 .sin_addr dd sin_addr; 192.168.0.17 } sockaddr_in sockaddr 0x02,0x05B5,0x1100A8C0 sizeSockaddr = 0x02+0x05B5+0x1100A8C0 section '.text' executable _start: ;socket mov rax,0x29 ;socket mov rdi, AF_INET mov rsi, SOCK_STREAM mov rdx, IPPROTO_TCP syscall mov rbx,rax ;binding mov rax,0x31 ;bind mov rdi,rbx lea rsi,[sockaddr_in] mov rdx,sizeSockaddr syscall ;listening mov rax,0x32 ; listen mov rdi,rbx ;descriptor mov rsi,1 syscall ;accept mov rax,43 ;accept mov rdi,rbx ;descriptor syscall ;welcome mov rax,1 mov rdi,1;sys_write mov rsi,message mov rdx,message_lenght syscall ;close socket mov rax,3 ;close mov rbx,rdi syscall ;exit program mov rax,60 mov rdi,0 syscall
问题分析
- sizeSockaddr计算完全错误:当前代码将结构体成员的数值相加得到地址长度,这不符合结构体大小的计算逻辑。sockaddr_in的标准大小是16字节,正确计算方式应为
sizeSockaddr = $ - sockaddr_in,用结构体结束位置减起始位置得到实际字节数,错误的长度会直接导致bind调用失败。 - IP地址字节序错误:192.168.0.17的网络字节序(大端)十六进制值为
0xC0A80011,代码中写的0x1100A8C0是小端存储的内存布局,直接赋值会导致实际绑定IP变为17.0.168.192,而非预期地址。 - 端口字节序错误:要绑定的1461端口,网络字节序需将主机小端序转换为大端序,正确值应为
0xB505,代码中使用的0x05B5会导致实际绑定端口变为46341,而非目标端口。 - 缺少错误检查:未对socket、bind、listen等系统调用的返回值做校验,无法快速定位调用失败环节。
- accept参数未初始化:原始代码中accept的rsi和rdx参数未赋值,可能引发未定义行为。
修正后的代码
format ELF64 section '.data' IPPROTO_TCP equ 0x06 SOCK_STREAM equ 0x01 AF_INET equ 0x02 message db 'welcome',0xA,0 message_length = $-message ; 定义标准sockaddr_in结构体,补充填充字段保证大小为16字节 struc sockaddr_in .sin_family dw ? .sin_port dw ? .sin_addr dd ? .pad rb 8 endstruc ; 初始化:AF_INET协议、1461端口(网络字节序0xB505)、192.168.0.17(网络字节序0xC0A80011) sockaddr_in_inst sockaddr_in AF_INET, 0xB505, 0xC0A80011 sizeSockaddr = $ - sockaddr_in_inst ; 正确计算结构体大小 section '.text' executable _start: ; 创建socket mov rax, 0x29 mov rdi, AF_INET mov rsi, SOCK_STREAM mov rdx, IPPROTO_TCP syscall test rax, rax js exit_on_error mov rbx, rax ; 绑定地址 mov rax, 0x31 mov rdi, rbx lea rsi, [sockaddr_in_inst] mov rdx, sizeSockaddr syscall test rax, rax js exit_on_error ; 监听连接 mov rax, 0x32 mov rdi, rbx mov rsi, 1 syscall test rax, rax js exit_on_error ; 接受连接,忽略客户端地址 mov rax, 0x2B mov rdi, rbx xor rsi, rsi xor rdx, rdx syscall test rax, rax js exit_on_error mov rcx, rax ; 向客户端发送欢迎消息 mov rax, 1 mov rdi, rcx mov rsi, message mov rdx, message_length syscall ; 关闭客户端socket mov rax, 3 mov rdi, rcx syscall ; 关闭监听socket mov rax, 3 mov rdi, rbx syscall ; 正常退出 mov rax, 60 mov rdi, 0 syscall exit_on_error: ; 错误退出,返回码1 mov rax, 60 mov rdi, 1 syscall
关键修正说明
- 结构体添加
pad字段,确保sockaddr_in大小符合Linux系统要求的16字节。 - 端口和IP均使用正确的网络字节序值,保证绑定的是预期的192.168.0.17:1461。
- 新增错误检查逻辑,系统调用失败时立即退出并返回错误码,便于排查问题。
- 补全accept的参数初始化,避免未定义行为。
内容的提问来源于stack exchange,提问作者whateveron
相关产品推荐
相关产品推荐

