⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 对一个用win32asm编写的tcp端口扫描程序的分析.txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 2 页
字号:
标 题: 【原创】对一个用Win32Asm编写的TCP端口扫描程序的分析
作 者: jhkdiy
时 间: 2006-03-25,00:35
链 接: http://bbs.pediy.com/showthread.php?t=23110

作者:jhkdiy
邮件:jhkdiy_gzb@21cn.net
论坛:www.20cn.net
日期:06年3月24日

    有一段时间没有去过ASMCommunity Messageboard(http://www.asmcommunity.net/board/index.php)了,以前直接可以访问。
现在只能通过代理才能访问,至少我这边是这样。在里面随便逛了逛,无意看到一位论坛会员问怎样用Asm来做一个端口扫描器,
结果其他会员给了一个源代码,在window的控制台窗口下运行,以阻塞模式扫描一个目标主机的端口。我觉得这个代码对刚学习
Windows Socket编程的朋友来说很有启发性,所以现在详细讲解一下这份代码,希望对大家有所帮助。若各位读者想先试试该程序
可以先用RadAsm建立一个console工程,然后将下面的代码粘贴到asm文件中,编译&链接。在控制台下运行该程序即可。
源代码如下,只做了一点的格式编排:

代码:
; Conscan - CLI "test"
.386 
.model flat, stdcall 
option casemap :none

include windows.inc 
include user32.inc 
include kernel32.inc 
include masm32.inc
include wsock32.inc
includelib user32.lib 
includelib kernel32.lib 
includelib masm32.lib
includelib wsock32.lib

print macro lpszText:VARARG
 local txt
 .data
  txt db lpszText,13,10,0
 .code
  invoke StdOut,addr txt
ENDM

SOCKADDR_IN struct
 sin_family WORD ?
 sin_port WORD ?
 sin_addr DWORD ?
 sin_zero BYTE 8 dup (?)
SOCKADDR_IN ends

.data
 szusg db "usage: conscan <hostname>",13,10,0
 fmt   db "%d OPEN",13,10,0
 sa    SOCKADDR_IN <>
 wsa   WSADATA <>
 sfd   dd 0
 port  dd 0
 pl    dd 21
       dd 22
       dd 23
       dd 25
       dd 80
       dd 137
       dd 350
       dd 8080
       dd 6667
       dd 31337
       dd 0
     
.data?
 hostname db 2024 dup (?)
 buffer   db 100 dup (?)
 
.code
conscan:
 call main
 call ExitProcess

main proc
    invoke GetCL,1,addr hostname
    cmp eax,1
    jne Arg_Error
    
    mov sa.sin_family, AF_INET
    lea edi,pl
Port_Scan_Loop:
    mov eax,[edi]
    cmp eax,0
    je Port_Scan_Complete
    inc edi
    mov port,eax
    invoke WSAStartup,101h,addr wsa
    invoke socket, AF_INET, SOCK_STREAM, 0
    mov sfd,eax
    invoke htons, port
    mov sa.sin_port, ax
    invoke gethostbyname, addr hostname   
    mov eax,[eax+12]
    mov eax,[eax]
    mov eax,[eax] 
    mov sa.sin_addr,eax
    invoke connect,sfd,addr sa,SIZEOF sa
    cmp eax, 0
    jne Port_Closed
    invoke wsprintf,addr buffer,addr fmt,port
    invoke StdOut,addr buffer
Port_Closed:
    invoke closesocket,sfd
    call WSACleanup
    jmp Port_Scan_Loop
Arg_Error:
    invoke StdOut,addr szusg
    ret
Port_Scan_Complete:
    print "-- Scan Complete --"
    ret
main endp
end conscan
整份代码才100行左右,那么,这短短的100行代码到底做了些什么呢?首先请将代码看一遍,
如果是似明非明的话就需要继续看下面的解释了。我们就一段段来分析吧,首先是第一部分:
.386 
.model flat, stdcall 
option casemap :none

include windows.inc 
include user32.inc 
include kernel32.inc 
include masm32.inc
include wsock32.inc
includelib user32.lib 
includelib kernel32.lib 
includelib masm32.lib
includelib wsock32.lib

开头的部分相信任何一位学win32asm的朋友都能看懂,include 和 includelib的部分确实有需要
留意的部分,那就是:
include wsock32.inc
includelib wsock32.lib

编写windows socket程序就要包含相应的windows socket头文件和库文件,当前可以使用的winsock
接口动态链接库版本有1.1版本和2.0版本。wsock32.inc & wsock32.lib 文件表示使用32位的
1.1版本的winsock,如果是使用2.0的winsock就需要使用WS2_32.inc 和 WS2_32.lib 文件。如果
对masm32.inc也不熟悉的话,在这里简单的说说,它是一系列常用的宏和函数的集合,主要是为了
编程方便,减少重复编写同样的代码而做的,包含了许多实用的宏和函数,在这个代码中StdOut等函数
就使用了这个文件。

再往下看,看到了一个宏:
print macro lpszText:VARARG
 local txt
 .data
  txt db lpszText,13,10,0
 .code
  invoke StdOut,addr txt
ENDM
该宏即使用了masm32.inc中的StdOut函数,该函数在windows标准控制台下输出一段文本,有点像C语言下的
printf()函数。紧跟着看到一段结构体定义:
SOCKADDR_IN struct
     sin_family WORD ?
     sin_port WORD ?
     sin_addr DWORD ?
     sin_zero BYTE 8 dup (?)
SOCKADDR_IN ends

该结构用来将套接字绑定到IP地址和端口使用,当然在后续的接受和发送等等的工作中都会用到。各字段注释
如下:

SOCKADDR_IN struct
     sin_family WORD ?              ;地址格式
     sin_port WORD ?                ;端口号(使用网络字节顺序)
     sin_addr DWORD ?               ;IP地址(使用网络字节顺序)
     sin_zero BYTE 8 dup (?)        ;空字节
SOCKADDR_IN ends

sin_family在不同的操作系统下有不同的值,但winsock环境一般都固定为 AF_INET,也可以是PF_INET,在windows.inc
中被定义为与AF_INET同样的值。sin_port 和 sin_addr 字段分别指定端口号和IP地址,放入这两个字段的数据字节
顺序必须是Internet顺序。这到底是怎么一回事呢?学过汇编语言的朋友都知道,Intel的CPU对内存操作数使用的是小尾
顺序,这种方式是将位数高的字节排在内存地址高的位置,而位数低的字节排在内存的低地址处,例如 12345678h ,
如果以字类型来存储,在内存表示为 78h 56h 34h 12h。如果以双字来存储,表示为5678h 1234h。而其它的CPU如Motorola
的CPU使用的是大尾顺序,这种顺序刚好相反,低位数排在内存的高位,高位数排在内存的低位,例如 12345678h表示为
12h 34h 56h 78h,这种方式比较适合我们一般的看书习惯,都是从左到右一路看过去。
本来这些东东不关我们事的,但是当两种不同CPU的主机通讯时就不行了,而Internet协议是一组开放的协议,需要在不同的
计算机平台之间进行通信,所以在实现时不能包含与特定平台有关的东西,即做到平台无关性。这就需要采用一种共同的数据
排列顺序才行,而Internet协议采用了大尾顺序,所以凡是80X86平台的winsock编程,当使用IP地址和端口号等参数时,都需要
将它们转换为大尾顺序。

好了,到了数据定义的内容了,我们看看都定义了什么:
.data
 szusg db "usage: conscan <hostname>",13,10,0       ;使用帮助
 fmt   db "%d OPEN",13,10,0                         ;输出时显示打开的端口
 sa    SOCKADDR_IN <>                               ;使用connect函数时用到
 wsa   WSADATA <>                                   ;使用WSAStartup函数时用到
 sfd   dd 0                                         ;保存Socket句柄
 port  dd 0                                         ;保存要扫描的端口
 pl    dd 21                                        ;这是程序将要扫描的端口列表
       dd 22
       dd 23
       dd 25
       dd 80
       dd 137
       dd 350
       dd 8080
       dd 6667
       dd 31337
       dd 0
     
.data?
 hostname db 2024 dup (?)           ;用于存贮域名
 buffer   db 100 dup (?)            

在.data段中,值得注意的是 定义了 一个 SOCKADDR_IN 类型的 sa变量,还有一个就是 WSADATA型的 wsa变量
WSADATA是用来初始化winsock库的,在使用winsock函数之前必须先使用WSAStartup函数来装入并初始化动态连接
库WS2_32.dll。例如在代码段中的     invoke WSAStartup,101h,addr wsa 即表示使用1.1版本的socket并初始化。
在端口列表pl方面,这种直接定义在程序内部的方式缺少了灵活性,如果能将常扫描的端口存入一个文件里,需要
扫描的时候才读入端口列表来扫描就好多了,注意,最后一个0是不能缺少的,实际上它表示端口列表的终止,而并

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -