Go红队开发—CLI框架(一)

news2025/4/22 7:04:14

CLI开发框架

命令行工具开发,主要是介绍开发用到的包,集成了一个框架,只要学会了基本每个人都能开发安全工具了。

该文章先学flags包,是比较经典的一个包,相比后面要学习的集成框架这个比较自由比较细化点,自定义可能高一些,后续会学到一个Cobra框架,这个很多安全工具都在使用,先学会flags包入门再去理解Cobra框架就比较好学。

flags包

  • 支持段选项长选项
    意思是使用的时候可以用简写也可以用完整的参数写,比如一个工具叫a.exe,用的时候可以a.exe -h 也可以 a.exe -help
  • 支持短选项组合写,比如:a.exe -p a.exe -s 两种可以写在一起:a.exe -ps
  • 一个参数选项可以给多个值(代码中很容易了解到这一点)
  • flags包默认有-h选项,解析完后–help和-h会返回你的所有参数解释,不用自己写help

安装

go get github.com/jessevdk/go-flags

个人感觉学习这个框架只需要理解两步:

  • 指定结构体选项
  • 解析结构体

基础的选项:随便写几个展示即可

  • short:短选项名字
  • long:长选项名字
  • description:显示你当前选项的一个解释,-help或者-h的时候显示
  • tips:
// 参数选项

type Option struct {

    //所有结构体首字母一定要大写,否则解析不了,但是short或者long的名字就随便你起

    V     string   `short:"v" long:"verbose" description:"显示详细信息"`

    Vlist []string `short:"V" long:"verbose-list" description:"显示详细信息列表"`

    I     int      `short:"i" long:"input" description:"int类型测试"`

    //这里可以给了一个默认值default:"xxx",不给的话在不使用该参数的时候就不用调用那个函数

    P      func(string)   `short:"p" long:"print" description:"打印"` // default:"myPrint"

    IntMap map[string]int `short:"m" long:"intmap" description:"intmap"`

}

函数这里是要给一个函数传递进去使用,具体如下:
是在你实例化你的选项结构体后,将你写好的函数传递进去,或者你写一个匿名函数也行。

// 打印功能

func myPrint(str string) {

    fmt.Println("打印-p参数值:", str)

}
func main() {
	var opt Option  //定义一个选项
	opt.P = myPrint //把打印函数赋值给P
}

使用的时候就可以用该参数了,传递的参数值就是给到函数变量使用的:

参数传递格式

  • -V传递:-V 123 -V 456 -V 789
    这样才能传递进map里面,不可以使用逗号或者空格隔开-V 123 456 / -V 123,456都是不行的
  • map的传递:-m key1:123 -m key2:456,不建议使用等号=,至少我在windows测试的时候等号不能作为键值对分割,只能使用:分割,同时多个map键值对也是多个-m才能传递添加进去。

剩下几个类型自己实践即可,这里就够用了。


选项设置

选项设置都是直接在结构体选项反引号中直接添加即可,他会解析的。

  • required:在结构体选项中可设置,true的时候,该选项必选,否则报错,一定要给这个选项一个值
    比如:
    V  string   short:"v" long:"verbose" description:"显示详细信息" required:true

  • default:表示你这个选项参数有一个默认值,就算你不加他也会以默认值形式作用本次运行
    比如:上面结构体代码注释其实有提到
    P  func(string)   short:"p" long:"print" description:"打印" default:"myPrint"
    这里就是可以给一个default,表示这个选项的默认值是多少,可以看到我这里给的是一个函数名,这个函数名我也在代码这种实现了吗,所以运行的时候肯定是可以找到我这个函数然后执行

分组

这个功能比较好用,至少对我来说以后开发构思中肯定需要用到这个,以及后面讲的子命令都是在一些比较完整的工具开发中用的比较多。

先看运行的效果图

这里和之前的不一样了,之前的没有分组的时候就是直接把一些参数打印出来,这里会有参数分组,对比之下会更加直观一点。

分组的结构体之间的联系是比较紧密的

  • 先创建好组名(组名也要用结构体)
    结构体内的字段都是你接下来要创建的结构体选项,所以在这里可以先提前想好选项的结构体名字
    比如下面的就是HostScan就是我们接下来要创建的分组的选项参数结构体
    group就是组名,到时候你在help中就能看到分组的组名
    namespace是空间名,在help中显示为Host.xxx选项,就是类似这样,主要是告诉你哪个组下的选项,重要是group是组名即可,显示的时候比较明显。
// basic 分组

type Basic struct {

    HostOption Host `group:"host" namespace:"Host"`

    ScanOption Scan `group:"scan" namespace:"Scan"`

}
  • 正常创建你在分组的时候想好的那几个结构体字段,我们给的名字是:HostScanOption,那么接下来就是写这两个结构体了
    注意:我在Scan中又开了一个组ScanType,所以还要写一个ScanType的结构体
    这是help效果图,应该很容易理解是怎么分组的了,也知道那个namespace是什么了,注意区分Hosthost,host是分组的组名,Host才是那个namespace。
type Host struct {

    HostName string `short:"N" long:"hostname" description:"主机名"`

    HostMac  string `short:"M" long:"hostmac" description:"主机mac"`

}

  

// 在扫描类型中继续分组

type ScanType struct {

    HttpType string `short:"T" long:"http" description:"http扫描"`

    DataBase string `short:"D" long:"database" description:"数据库扫描"`

    Other    string `short:"O" long:"other" description:"其他扫描"`

}

type Scan struct {

    BasicScan ScanType `group:"scantype" namespace:"scantype"`

    ScanPort  int      `short:"P" long:"scanport" description:"扫描端口"`

    ScanIP    string   `short:"I" long:"scanip" description:"扫描ip"`

}

子命令

简单的来说:go version 这个 version就是子命令,不用带-,直接用的就是子命令,-version 这种带-的就是选项而不是子命令哈,注意一个符号的区别。


同时记住一点:子命令在flags包中也自动实现了-h /h命令,所以不用编写帮助信息。
(但是你想要实现不添加-h /h 就实现比如 xx.exe finger 也能给出帮助信息的话就要在接口中实现了,后续会在finger中讲明白)

version
  • 先实现version子命令
    继承了flags.Command的Execute接口就成功实现了子命令了,只剩下注册到主要的结构体中,也就是之前学到的需要一个结构体注册选项
    (tips:version的结构体为空,不是拿来切割或者分组,只是一个显示版本号,后面讲finger的时候他才是作为这个分组命令来弄)
//给一个空的,因为version一般都不需要什么其他参数来辅助就可以看到版本了
type ChildCommand struct {

}

// 继承了flags.Command即可自动调用

func (c *ChildCommand) Execute(args []string) error {

  

    fmt.Println("version: 1.0.0")

  

    return nil

}
  • 注册子命令到主选项结构体中,这里才是给到flags解析的结构体,注意这里给的键不再是short/long,而是command
type VOption struct {

    Version ChildCommand `command:"version" description:"Version显示版本信息"`

}

运行效果没问题(源码稍后放)

finger(测试)

finger来加深理解
一般指纹识别的都是xx.exe finger -u xxx -p xxx
所以我认为用这个例子非常好

  • 依旧是先做好一个子命令,但是这里要给子命令上两个选项,用来指纹识别的ip和端口
    同时要记得实现接口Execute
// 模拟一下指纹扫描中常见的一个子命令

type Finger struct {

    U string `short:"u" long:"url" description:"url"`

    P string `short:"p" long:"port" description:"port"`

}

func (c *Finger) Execute(args []string) error {
    if c.U == "" || c.P == "" {
        // 如果没有提供参数,显示帮助信息,尽量做的完美一点
        parser := flags.NewParser(c, flags.Default)
        parser.WriteHelp(os.Stdout)
        return nil
    }
    return nil

}
  • 在主结构体中注册这个子命令
    我就直接在之前的VOption结构体注册了
type VOption struct {
    Version ChildCommand `command:"version" description:"Version显示版本信息"`

    // 指纹扫描
    Finger Finger `command:"finger" description:"Finger指纹扫描"`

}

注册完成就可以用了

  • 加帮助参数
  • 这个没有加参数 -h 或者 /h等等

以上就是flags包的一些基础常用的内容了,拿到参数之后就是往后丢给你自己写的功能函数即可。

所有测试源码

test1 基础使用测试、test2分组测试 和 test3子命令 自己看着用就行。

package main

  

import (

    "fmt"

    "log"

    "os"

  

    "github.com/jessevdk/go-flags"

)

  

// 参数选项

type Option struct {

    //所有结构体首字母一定要大写,否则解析不了,但是short或者long的名字就随便你起

    V     string   `short:"v" long:"verbose" description:"显示详细信息"`

    Vlist []string `short:"V" long:"verbose-list" description:"显示详细信息列表"`

    I     int      `short:"i" long:"input" description:"int类型测试"`

    //这里可以给了一个默认值default:"xxx",不给的话在不使用该参数的时候就不用调用那个函数

    P      func(string)   `short:"p" long:"print" description:"打印"` // default:"myPrint"

    IntMap map[string]int `short:"m" long:"intmap" description:"intmap"`

}

  

// 打印功能

func myPrint(str string) {

    fmt.Println("打印-p参数值:", str)

}

  

// basic 分组

type Basic struct {

    HostOption Host `group:"host" namespace:"Host"`

    ScanOption Scan `group:"scan" namespace:"Scan"`

}

  

type Host struct {

    HostName string `short:"N" long:"hostname" description:"主机名"`

    HostMac  string `short:"M" long:"hostmac" description:"主机mac"`

}

  

// 在扫描类型中继续分组

type ScanType struct {

    HttpType string `short:"T" long:"http" description:"http扫描"`

    DataBase string `short:"D" long:"database" description:"数据库扫描"`

    Other    string `short:"O" long:"other" description:"其他扫描"`

}

type Scan struct {

    BasicScan ScanType `group:"scantype" namespace:"scantype"`

    ScanPort  int      `short:"P" long:"scanport" description:"扫描端口"`

    ScanIP    string   `short:"I" long:"scanip" description:"扫描ip"`

}

  

type ChildCommand struct {

}

  

// 继承了flags.Command即可自动调用

func (c *ChildCommand) Execute(args []string) error {

  

    fmt.Println("version: 1.0.0")

  

    return nil

}

  

// 模拟一下指纹扫描中常见的一个子命令

type Finger struct {

    U string `short:"u" long:"url" description:"url"`

    P string `short:"p" long:"port" description:"port"`

}

  

func (c *Finger) Execute(args []string) error {

    if c.U == "" || c.P == "" {

        // 如果没有提供参数,显示帮助信息

        parser := flags.NewParser(c, flags.Default)

        parser.WriteHelp(os.Stdout)

        return nil

    }

  

    return nil

}

  

type VOption struct {

    Version ChildCommand `command:"version" description:"Version显示版本信息"`

  

    // 指纹扫描

    Finger Finger `command:"finger" description:"Finger指纹扫描"`

}

  

func test3() {

    parser := flags.NewParser(&VOption{}, flags.Default)

    _, err := parser.Parse()

    if err != nil {

        if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {

            return // 帮助信息已打印,直接退出

        }

        //如果不是打印的帮助信息报错的话就直接log就行

        log.Println("parses failed: ", err)

        return

    }

  

}

  

func test1() {

    var opt Option  //定义一个选项

    opt.P = myPrint //把打印函数赋值给P

  

    parser := flags.NewParser(&opt, flags.Default)

    _, err := parser.Parse()

    if err != nil {

        if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {

            return // 帮助信息已打印,直接退出

        }

        //如果不是打印的帮助信息报错的话就直接log就行

        log.Println("parses failed: ", err)

        return

    }

  

    fmt.Println("--------------------------")

    fmt.Println("打印-v参数值:", opt.V)

    fmt.Println("打印-V 列表所有的参数值:", opt.Vlist)

    fmt.Println("打印-i参数值:", opt.I)

    fmt.Println("打印--intmap参数值:", opt.IntMap)

}

func test2() {

    var BasicOption Basic

    parser := flags.NewParser(&BasicOption, flags.Default)

    _, err := parser.Parse()

    if err != nil {

        if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {

            return // 帮助信息已打印,直接退出

        }

        //如果不是打印的帮助信息报错的话就直接log就行

        log.Println("parses failed: ", err)

        return

    }

    fmt.Println("--------------------------")

}

  

func main() {

    // test1()

    // test2()

    test3()

  

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2321408.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高效团队开发的工具与方法 引言

引言 在现代软件开发领域,团队协作的效率和质量直接决定了项目的成败。随着项目规模的扩大和技术复杂度的增加,如何实现高效团队开发成为每个开发团队必须面对的挑战。高效团队开发不仅仅是个人技术能力的简单叠加,更需要借助合适的工具和方…

【Java全栈进阶架构师实战:从设计模式到SpringCloudAlibaba,打造高可用系统】

🌟 分享一个教程,助刚踏入IT行业、工作几年的老油条、或热爱学习的工作党们更上一层楼的! 🌟 ​适合人群:初中级Java开发者、求职面试备战者、技术提升党! 📚 ​内容亮点: 1️⃣ ​…

[蓝桥杯 2023 省 A] 异或和之和

题目来自洛谷网站&#xff1a; 暴力思路&#xff1a; 先进性预处理&#xff0c;找到每个点位置的前缀异或和&#xff0c;在枚举区间。 暴力代码&#xff1a; #include<bits/stdc.h> #define int long long using namespace std; const int N 1e520;int n; int arr[N…

TDengine 3.3.2.0 集群报错 Post “http://buildkitsandbox:6041/rest/sql“

修复&#xff1a; vi /etc/hosts将buildkitsandbox映射为本机节点

vue数据重置

前言 大家在开发后台管理系统的过程中&#xff0c;一定会遇到一个表格的条件查询重置功能吧&#xff0c;如果说查询条件少&#xff0c;重置起来还算是比较简单&#xff0c;如果元素特别多呢&#xff0c;那玩意写起来可遭老罪喽&#xff0c;那今天就给大家整一个如何快速重置数…

git revert 用法实战:撤销一个 commit 或 merge

git revert 1 区别 • 常规的 commit &#xff08;使用 git commit 提交的 commit&#xff09; • merge commit 2 首先构建场景 master上的代码 dev开发分支上&#xff0c;添加一个a标签&#xff0c;并commit这次提交 切到master上&#xff0c;再次进行改动和提交 将de…

修形还是需要再研究一下

最近有不少小伙伴问到修形和蜗杆砂轮的问题&#xff0c;之前虽然研究过一段时间&#xff0c;但是由于时间问题放下了&#xff0c;最近想再捡起来。 之前计算的砂轮齿形是一整段的&#xff0c;但是似乎这种对于有些小伙伴来说不太容易接受&#xff0c;希望按照修形的区域进行分…

AI本地部署之dify

快捷目录 Windows 系统一、环境准备:首先windows 需要准备docker 环1. 安装Docker desktop2. 安装Docker3. 配置Docker 镜像路径4. 配置Docker 下载镜像源5. 重启Docker服务二、Dify 下载和安装1. Dify下载2. Dify 配置3. Dify 安装附件知识:4. Dify创建账号三、下载Ollama d…

安恒春招一面

《网安面试指南》https://mp.weixin.qq.com/s/RIVYDmxI9g_TgGrpbdDKtA?token1860256701&langzh_CN 5000篇网安资料库https://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247486065&idx2&snb30ade8200e842743339d428f414475e&chksmc0e4732df793fa3bf39…

Python应用指南:利用高德地图API获取POI数据(关键词版)

都说“为一杯奶茶愿意赴一座城”&#xff0c;曾经不知有多少年轻人为了一口茶颜悦色不惜跨越千里来到长沙打卡&#xff0c;而如今也有不少年轻人被传说中的“奶茶界的海底捞”所吸引&#xff0c;千里迢迢来到安徽只为尝一口卡旺卡奶茶。要说起来这卡旺卡奶茶&#xff0c;尽管这…

Linux网络相关概念和重要知识(2)(UDP套接字编程、聊天室的实现、观察者模式)

目录 1.UDP套接字编程 &#xff08;1&#xff09;socket编程 &#xff08;2&#xff09;UDP的使用 ①socket ②bind ③recvfrom ④sendto 2.聊天室的实现 &#xff08;1&#xff09;整体逻辑 &#xff08;2&#xff09;对sockaddr_in的封装 &#xff08;3&#xff09…

JVM 03

今天是2025/03/24 15:21 day 11 总路线请移步主页Java大纲相关文章 今天进行JVM 5,6 个模块的归纳 首先是JVM的相关内容概括的思维导图 5. 优化技术 JVM通过多种优化技术提升程序执行效率&#xff0c;核心围绕热点代码检测和编译优化实现动态性能提升。 热点代码检测 JVM…

【VUE】day07 路由

【VUE】day07 路由 1. 路由2. 前端路由的工作方式3. 实现简易的前端路由4. 安装和配置路由4.1 安装vue-router包4.2 创建路由模块4.3 导入并挂在路由模块 5. 在路由模块中声明路由的对应关系5.1 router-view 1. 路由 在 Vue.js 中&#xff0c;路由&#xff08;Routing&#xf…

内网穿透的应用-本地部署ChatTTS教程:Windows搭建AI语音合成服务的全流程配置

文章目录 前言1. 下载运行ChatTTS模型2. 安装Cpolar工具3. 实现公网访问4. 配置ChatTTS固定公网地址 前言 各位开发者小伙伴们&#xff01;今天我要给大家推荐一个超级火的AI项目——ChatTTS。这个开源文本转语音&#xff08;TTS&#xff09;项目的火爆程度简直让人难以置信&a…

2025-03-21 Unity 网络基础3——TCP网络通信准备知识

文章目录 1 IP/端口类1.1 IPAddress1.2 IPEndPoint 2 域名解析2.1 IPHostEntry2.2 Dns 3 序列化与反序列化3.1 序列化3.1.1 内置类型 -> 字节数组3.1.2 字符串 -> 字节数组3.1.3 类对象 -> 字节数组 3.2 反序列化3.2.1 字节数组 -> 内置类型3.2.2 字节数组 -> 字…

静态时序分析:SDC约束命令set_min_pulse_width详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 最小脉冲宽度检查用于确保一个单元的时钟引脚和异步置位/复位引脚的的脉冲宽度满足最小要求&#xff0c;如果违反该要求&#xff0c;则可能出现功能错误。严格意…

推荐1款简洁、小巧的实用收音机软件,支持手机和电脑

聊一聊 没想到现在还有人喜欢听广播。 我一直以为听广播必须要用那种小广播机才可以。 原来手机或电脑上也是可以的。 今天给大家分享一款可以在电脑和手机上听广播的软件。 软件介绍 龙卷风收音机 电台广播收音机分电脑和手机两个版本。 电脑端无需安装&#xff0c;下载…

HO与OH差异之Navigation

在上一篇的内容中我们进一步的了解了Navigation的用法&#xff0c;但是既然写到这里了我就再来扩充一下有关Navigation的内容。 HarmonyOS与OpenHarmony之间有些写法与内容是有差异的&#xff0c;就比如Navigation的跳转。以下内容中HarmonyOS我都简称为HO&#xff0c;OpenHar…

模糊规则激活方法详解(python实例对比)

前文我们已经了解了多种隶属函数&#xff0c;如三角形、梯形、高斯型、S型和Z型&#xff0c;并且讨论了模糊推理的基本过程&#xff0c;包括模糊化、规则评估、聚合和解模糊化。我们还了解了如何生成模糊规则的方法&#xff0c;比如专家经验、聚类分析、决策树、遗传算法和ANFI…

Web前端考核 JavaScript知识点详解

一、JavaScript 基础语法 1.1 变量声明 关键字作用域提升重复声明暂时性死区var函数级✅✅❌let块级❌❌✅const块级❌❌✅ 1.1.1变量提升的例子 在 JavaScript 中&#xff0c;var 声明的变量会存在变量提升的现象&#xff0c;而 let 和 const 则不会。变量提升是指变量的声…