分析某款go端口扫描器之一

2023-11-30 18:36
文章标签 分析 go 端口扫描 某款

本文主要是介绍分析某款go端口扫描器之一,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、概述

        进来在学go的端口检测部分,但是自己写遇到很多问题,又不知道从何入手,故找来网上佬们写的现成工具,学习一波怎么实现的。分析过程杂乱,没啥思路,勿喷。

项目来源:https://github.com/XinRoom/go-portScan/blob/main/util/file.go

二、目录结构分析

总体来说,这个工具主要三部分,cmd(主程序)、core(核心框架部分)、util(工具部分),后续的分析也从这三个部分开始讲解

三、util目录

此目录下主要有三个文件,分别为file.go、log.go、shuffle.go,以下逐一分析

1、file.go(逐行读取文件内容)

  • func GetLines(filename string) (out []string, err error)

主要内容为一个GetLines方法,其接收一个文件名作为参数,并返回文件中非空行的内容组成字符串切片和可能的错误,主要作用是逐行读取文件,并将非空行的内容添加到“out"切片中。

func GetLines(filename string) (out []string, err error) {if filename == "" {//先判断文件名是否为空,为空则提示错误return out, errors.New("no filename")}file, err := os.Open(filename)//打开文件if err != nil {return out, err}defer file.Close()//读取完记得关闭scanner := bufio.NewScanner(file)//读取文件的内容scanner.Split(bufio.ScanLines)//一行一行读取分隔for scanner.Scan() {//逐行读取并将文本内容追加到out切片中line := strings.TrimSpace(scanner.Text())if line != "" {out = append(out, line)}}return
}

2、log.go(日志记录)

  • func NewLogger(filename string, std bool) *log.Logger

主要内容为一个 NewLogger方法,它根据提供的参数创建一个新的日志记录器对象。该函数接受一个文件名和一个布尔值参数。

  • filename 参数用于指定日志输出的文件名,如果为空字符串则表示日志将输出到标准输出(stdout)。
  • std 参数是一个布尔值,如果设置为 true,则日志会同时输出到文件和标准输出;如果设置为 false,则只输出到文件。

这个函数的目的是根据参数创建一个日志记录器,可以指定输出到文件还是标准输出,并可以选择是否同时输出到文件和标准输出。

func NewLogger(filename string, std bool) *log.Logger {var out io.Writerif filename == "" {out = os.Stdout //如果传入的filename为空,将out设置为标准输出} else {//如果不为空,则打开这个文件,outFile, _ := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)if std {//如果 std为true,则将输出同时定向到标准输出和文件中,通过 io.MultiWriter 将os.Stdout 和打开的文件合并成一个多写入器out = io.MultiWriter(os.Stdout, outFile)} else {//如果 std 参数为 false,则直接将输出定向到打开的文件中out = outFile}}logger := log.New(out, "", 0)//使用 log.New 方法创建一个新的日志记录器对象 logger,将输出对象 out 作为日志记录器的输出,设置空的前缀,并且不添加任何额外的选项(flag)return logger
}

3、shuffle.go

主要包含3个方法:NewShuffle、Get、IsUint16InList,以及一个结构体Shuffle

  • type Shuffle struct

type Shuffle struct {rl   []uint16 // 乱序序列,存储的是一般轮次的乱序序列rl2  []uint16 // 最后一轮乱序序列(无法整除时使用)n    uint16   // 乱序精度,用来限制乱序序列的长度size uint64    //乱序序列的大小
}
  • func NewShuffle(size uint64) *Shuffle

函数接收一个 size 参数作为生成乱序序列的大小。

// NewShuffle 局部乱序
func NewShuffle(size uint64) *Shuffle {if size == 0 { //如果size为0, 返回nilreturn nil}sf := &Shuffle{size: size}// 创建一个新的 Shuffle 结构体,设置其 size 字段为传入的值if size > 100 {sf.n = 100 //如果size>100,设置乱序精度为100} else {sf.n = uint16(size)//否则设置乱序精度为size 的 uint16 类型。}//通过循环填充 rl 切片,创建一般轮次的乱序序列。//使用 rand 包生成随机数种子,对 rl 进行乱序化操作。//如果 size 无法整除 n,则设置 rl2 切片,并生成最后一轮乱序序列// 通用轮次sf.rl = make([]uint16, sf.n)for i := uint16(0); i < sf.n; i++ {sf.rl[i] = i}// 洗牌方法r := rand.New(rand.NewSource(int64(size)))r.Shuffle(int(sf.n), func(i, j int) {sf.rl[i], sf.rl[j] = sf.rl[j], sf.rl[i]})// 最后一轮无法整除时新建对应长度的rl2t := uint16(size % uint64(sf.n))if t != 0 {sf.rl2 = make([]uint16, t)for i := uint16(0); i < t; i++ {sf.rl2[i] = i}r.Shuffle(int(t), func(i, j int) {sf.rl2[i], sf.rl2[j] = sf.rl2[j], sf.rl2[i]})}return sf
}
  • func (sf *Shuffle) Get(index uint64) uint6

Get 方法接收一个索引 index,用于获取转换后的索引值。首先计算 t 为 index 对 sf.n 取模得到的结果。然后根据索引 index 与 n 的关系,决定使用哪个乱序序列。如果无法整除,则使用 rl2,否则使用 rl

// Get 根据索引获取转换后的索引值
func (sf *Shuffle) Get(index uint64) uint64 {t := index % uint64(sf.n)// 最后一轮无法整除时用rl2if index-t+uint64(sf.n) > sf.size {return index - t + uint64(sf.rl2[uint16(t)])}return index - t + uint64(sf.rl[uint16(t)])
}
  • func IsUint16InList(code uint16, list []uint16) bool

IsUint16InList 函数接收一个 code 和一个 list,用于判断 list 中是否存在 code。

它遍历 list 切片,如果发现存在与 code 相等的元素,则返回 true;如果遍历完 list 后都没有找到,则返回 false。

func IsUint16InList(code uint16, list []uint16) bool {for _, e := range list {if e == code {return true}}return false
}

这篇关于分析某款go端口扫描器之一的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/438103

相关文章

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

Go Gorm 示例详解

《GoGorm示例详解》Gorm是一款高性能的GolangORM库,便于开发人员提高效率,本文介绍了Gorm的基本概念、数据库连接、基本操作(创建表、新增记录、查询记录、修改记录、删除记录)等,本... 目录1. 概念2. 数据库连接2.1 安装依赖2.2 连接数据库3. 数据库基本操作3.1 创建表(表关

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

Go信号处理如何优雅地关闭你的应用

《Go信号处理如何优雅地关闭你的应用》Go中的优雅关闭机制使得在应用程序接收到终止信号时,能够进行平滑的资源清理,通过使用context来管理goroutine的生命周期,结合signal... 目录1. 什么是信号处理?2. 如何优雅地关闭 Go 应用?3. 代码实现3.1 基本的信号捕获和优雅关闭3.2

Spring中Bean有关NullPointerException异常的原因分析

《Spring中Bean有关NullPointerException异常的原因分析》在Spring中使用@Autowired注解注入的bean不能在静态上下文中访问,否则会导致NullPointerE... 目录Spring中Bean有关NullPointerException异常的原因问题描述解决方案总结