首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

编译

obsd32# gcc -o rpc1 rpc1.c

执行

执行结果 

obsd32# ./rpc1

rpc1 00.00.01

usage  : ./rpc1 -t target_ip -p port_range

example: ./rpc1 -t 127.0.0.1 -p 1-1024

 

obsd32# ./rpc1 -t 10.0.8.16 -p 32770-32780

 

using: target: 10.0.8.16; lport: 32770; hport: 32780

 

RPC 100024 [000186B8] @ 10.0.8.16:32771

RPC 100002 [000186A2] @ 10.0.8.16:32772

RPC 100221 [0001877D] @ 10.0.8.16:32773

RPC 100083 [000186F3] @ 10.0.8.16:32775

RPC 300598 [00049636] @ 10.0.8.16:32776

RPC 100249 [00018799] @ 10.0.8.16:32777

scan complete.

rpc1.c程序通过命令行接收目标IP地址、起始TCP端口号、结束TCP端口号、connect()函数超时参数(以秒为单位)recv()函数超时参数以及详细信息(verbosity)标志。程序使用这些信息来发现从起始端口号到结束端口号之间的所有开放TCP端口并对所发现的每一个开放TCP端口进行一次RPC程序号识别操作。如果识别出了程序号,则在标准输出设备上打印出TCP端口号与识别出的程序号。

分析

       9行到第15行,载入所需的头文件。

       17行到第19行,定义程序要用到的几个常量,其中RPC1_CTO_TO常量定义了执行connect()函数允许的秒数,RPC1_RTO_TO常量定义了从远程端口等待接收数据允许的秒数。

       24行到第27行,声明一个无符号整型数组。这个数组列出了程序号识别程序用到的一些已知的RPC程序号,其中每一个数据都将发到RPC服务端。如果某个数据能与目标RPC服务的程序号相匹配,则该程序号就会被识别出来。要增加可识别的RPC程序号,只需将其他的程序号添加到数组中。

       44行到第89行,定义并实现hexdisp()函数。它有两个参数,第1个参数为一个指向缓冲区的指针,第2个参数为一个有符号整数,表示缓冲区的长度。这个函数将缓冲区中的字符转换成可读的格式并在标准输出设备上打印出来,格式与tcpdump程序在使用–X标志时的格式相似。

       97行到第101行,定义RCP请求数据报文,其中RPC1_ID_HEAD值稍后会被复制到一个缓冲区,后面紧跟着一个4字节的整数和PRC1_ID_TAIL值。这3个值组合起来就构成了一个有效的RPC请求报文。

       103行到第157行,定义并实现rpcidport()函数,它有2个参数:第1个参数为一个已通过connect()函数连接到目标端口的套接字描述符;第2个参数为一个整型指针,指向一个无符号整数,用于存放识别出的程序号;第3个参数为一个整数,指示rpcidport()函数是否打印出错信息。这个函数循环执行,对于第24行所声明的progid数组中的每一个程序号,利用前面定义的RPC1_ID_HEAD、程序号和RPC1_ID_TAIL三个值构造RPC请求报文。第124行,将RPC通过send()函数发送到目标端口。第134行,使用recv()接收目标端口的响应。如果收到的数据长度大于或等于28,则有足够的数据以供检查。第237行到第142行,检查响应信息中的6个字节,以确定前面发送的RPC请求是否包含了正确的RPC程序号。如果程序号正确,则函数将它存入id变量然后返回。

       164行到第221行,定义并实现makesock()函数。这个函数将目标IP地址从带点字符串格式转换为无符号整数格式,调用socket()函数创建一个用来收发TCP数据的套接字描述符,然后调用connect()函数将套接字连接到目标IP地址和端口。如果所有操作都成功,则函数会返回一个合法的套接字描述符,否则返回一个负整数。

       228行到第270行,定义并实现rpcid()函数。这个函数首先调用makesock()创建一个套接字描述符,然后调用rpcidport()函数识别RPC程序号,最后打印出IP地址、端口号以及rpcidport()函数执行成功时返回的RPC程序号。函数的第1个参数为目标主机的IP地址,第2个参数为目标端口,第3个参数为connect()函数的超时限制,第4个参数为recv()函数的超时限制,第5个参数为一个整数值,指示是否打印出错信息。

       277行到第310行,定义并实现scan()函数。这个函数接收6个参数:第1个参数为目标主机的IP地址,以点分字符串表示,并通过inet_addr()函数转换为无符号整型的格式;第2个参数为起始TCP端口号;第3个参数为结束TCP端口号;第4和第5个参数被直接传给rpcid()函数;第6个参数为一个整型值,指示是否打印出错信息。这个函数在指定的端口号范围内按从低到高的顺序循环执行,对于每一个端口,调用rpcid()函数识别在上面运行的RPC服务。

       317行到第344行,定义并实现parse()函数。这个函数将用户给出的端口号或端口号范围转换为短整型值。如果用户指定了单个端口号,则通过atoi()函数转换为无符号短整型,如果指定的是端口号范围,则先转换低端端口号,接着再转换高端端口号。

       351行到第353行,定义并实现sighandler()函数。这个函数将在程序收到SIGPIPESIGALRM信号时由操作系统调用。如果TCP连接的远程端关闭了连接,而应用试图向套接字写入数据,则就会收到SIGPIPE信号。当应用程序试图在一个没有运行RPC协议的TCP端口上识别RPC程序号时,也可以发生同样的情况。之所以要处理SIGPIPE信号,是因为在默认情况下,产生该信号时如果应用程序没有进行处理,操作系统将终止程序执行。当调用alarm()函数时,在指定的秒数超过以后,就会产生SIGALRM信号,所有等待操作完成的函数都会立即返回并得到一个错误值。这样,如果connect()函数的执行超过了调用alarm()函数时所指定的时间,则就会中止。rpc1.c程序的第188行使用alarm()函数实现了这种技术。

       360行到第365行,定义并实现usage()函数。这个函数用于在标准输出设备上打印关于程序用法的信息。

       368行到第438行,定义并实现main()函数,这是整个程序的入口。这个函数用于处理用户通过命令行给出的参数,并调用scan()函数进行扫描。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论