阅读go语言工具源码系列之gopacket(谷歌出品)----第一集 DLL的go封装

news2024/11/16 1:53:01

gopacket项目是google出品的golang第三方库,项目源码地址google/gopacket: Provides packet processing capabilities for Go (github.com)

gopacket核心是对经典的抓包工具libpcap(linux平台)和npcap(windows平台)的go封装,提供了更方便的go语言操作接口,里面如何实现的,接下来的文章中会有介绍。

windows平台和linux平台的go封装有些不一样
我们先从windows平台讲起吧(笔者常用操作系统为windows系统)

第一集 DLL的go封装

windows系统中使用的抓包工具是npcap,请提前到Npcap: Windows Packet Capture Library & Driver下载安装,安装完成后可在安装文件夹中看到在这里插入图片描述
其中wpcap.dll是本集中所要绑定的dll库

DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件被称为共享DLL文件。

在golang中使用syscall库来进行调用底层操作系统 API 的包。gopacket中采用的方式就是使用syscall来调用DLL文件。

├─afpacket          
├─bsdbpf            
├─bytediff
├─defrag
│  └─lcmdefrag      
├─dumpcommand
├─examples
│  ├─bidirectional
│  ├─bytediff
│  ├─httpassembly
│  ├─pcapdump
│  ├─pcaplay
│  ├─pfdump
│  ├─reassemblydump
│  ├─snoopread
│  ├─statsassembly
│  ├─synscan
│  └─util
├─ip4defrag
├─layers
│  └─testdata
│      └─fuzz
│          └─FuzzDecodeFromBytes
├─macs
├─pcap
│  └─gopacket_benchmark
├─pcapgo
│  └─tests
│      ├─be
│      └─le
├─pfring
├─reassembly
├─routing
└─tcpassembly
    └─tcpreader

在项目文件中pcap -> pcap_windows.go中即是对wpcap.dll的go封装代码

我们来看一下里面的构造

不知道大家看golang工具源码的时候是怎么一个顺序,个人比较喜欢按照执行顺序来先了解大致要干啥的逻辑,所以首先我们看一下init函数:

// init函数是每个文件首先执行的,甚至于在main.go 中也会早于main函数执行
func init() {  
	LoadWinPCAP()  
}

这个函数其实点明了本文件的主旨LoadWinPCAP导入winpcap。
按照执行顺序执行到了LoadWinPCAP()函数

// LoadWinPCAP attempts to dynamically load the wpcap DLL and resolve necessary functions// 动态导入wpcap.dll库  
func LoadWinPCAP() error {  
// 首先通过pcapLoaded变量来判断winpcap是否导入过,pcapLoaded变量初始化时为bool  
if pcapLoaded {  
return nil  
}  
// syscall.LoadLibrary 来导入kernel32.dll  
kernel32, err := syscall.LoadLibrary("kernel32.dll")  
if err != nil {  
return fmt.Errorf("couldn't load kernel32.dll")  
}  
//延迟释放kernel32.dll  
defer syscall.FreeLibrary(kernel32)  
  
//设置路径为npcap所在路径  
initDllPath(kernel32)  
// 使用syscall.GetProcAddress来获取kernel32中的AddDllDirectory函数  
if haveSearch, _ := syscall.GetProcAddress(kernel32, "AddDllDirectory"); haveSearch != 0 {  
// 如果存在 AddDllDirectory,我们可以将 LOAD_LIBRARY_* 的东西与 LoadLibraryEx 一起使用,以避免 wpcap .dll劫持  
// if AddDllDirectory is present, we can use LOAD_LIBRARY_* stuff with LoadLibraryEx to avoid wpcap.dll hijacking  
// see: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx  
const LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400  
const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800  
wpcapHandle, err = windows.LoadLibraryEx("wpcap.dll", 0, LOAD_LIBRARY_SEARCH_USER_DIRS|LOAD_LIBRARY_SEARCH_SYSTEM32)  
if err != nil {  
return fmt.Errorf("couldn't load wpcap.dll")  
}  
} else {  
// otherwise fall back to load it with the unsafe search cause by SetDllDirectory  
// 否则回退以使用 SetDllDirectory 导致的不安全搜索加载它  
wpcapHandle, err = windows.LoadLibrary("wpcap.dll")  
if err != nil {  
return fmt.Errorf("couldn't load wpcap.dll")  
}  
}  
initLoadedDllPath(kernel32)  
// 导入 msvcrt 动态库  
msvcrtHandle, err = syscall.LoadLibrary("msvcrt.dll")  
if err != nil {  
return fmt.Errorf("couldn't load msvcrt.dll")  
}  
// 引入calloc函数  
callocPtr, err = syscall.GetProcAddress(msvcrtHandle, "calloc")  
if err != nil {  
return fmt.Errorf("couldn't get calloc function")  
}  

// 将wpcap库函数进行绑定
// It returns an error message string corresponding to error.  
pcapStrerrorPtr = mustLoad("pcap_strerror")  
// get a string for an error or warning status code  
pcapStatustostrPtr = mightLoad("pcap_statustostr") // not available on winpcap  
// get a handle for a live capture  
pcapOpenLivePtr = mustLoad("pcap_open_live")  
pcapOpenOfflinePtr = mustLoad("pcap_open_offline")  
pcapClosePtr = mustLoad("pcap_close")  
pcapGeterrPtr = mustLoad("pcap_geterr")  
pcapStatsPtr = mustLoad("pcap_stats")  
pcapCompilePtr = mustLoad("pcap_compile")  
pcapFreecodePtr = mustLoad("pcap_freecode")  
pcapLookupnetPtr = mustLoad("pcap_lookupnet")  
pcapOfflineFilterPtr = mustLoad("pcap_offline_filter")  
pcapSetfilterPtr = mustLoad("pcap_setfilter")  
pcapListDatalinksPtr = mustLoad("pcap_list_datalinks")  
pcapFreeDatalinksPtr = mustLoad("pcap_free_datalinks")  
pcapDatalinkValToNamePtr = mustLoad("pcap_datalink_val_to_name")  
pcapDatalinkValToDescriptionPtr = mustLoad("pcap_datalink_val_to_description")  
pcapOpenDeadPtr = mustLoad("pcap_open_dead")  
pcapNextExPtr = mustLoad("pcap_next_ex")  
pcapDatalinkPtr = mustLoad("pcap_datalink")  
pcapSetDatalinkPtr = mustLoad("pcap_set_datalink")  
pcapDatalinkNameToValPtr = mustLoad("pcap_datalink_name_to_val")  
pcapLibVersionPtr = mustLoad("pcap_lib_version")  
pcapFreealldevsPtr = mustLoad("pcap_freealldevs")  
pcapFindalldevsPtr = mustLoad("pcap_findalldevs")  
pcapSendpacketPtr = mustLoad("pcap_sendpacket")  
pcapSetdirectionPtr = mustLoad("pcap_setdirection")  
pcapSnapshotPtr = mustLoad("pcap_snapshot")  
//libpcap <1.2 doesn't have pcap_*_tstamp_* functions  
pcapTstampTypeValToNamePtr = mightLoad("pcap_tstamp_type_val_to_name")  
pcapTstampTypeNameToValPtr = mightLoad("pcap_tstamp_type_name_to_val")  
pcapListTstampTypesPtr = mightLoad("pcap_list_tstamp_types")  
pcapFreeTstampTypesPtr = mightLoad("pcap_free_tstamp_types")  
pcapSetTstampTypePtr = mightLoad("pcap_set_tstamp_type")  
pcapGetTstampPrecisionPtr = mightLoad("pcap_get_tstamp_precision")  
pcapSetTstampPrecisionPtr = mightLoad("pcap_set_tstamp_precision")  
pcapOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_open_offline_with_tstamp_precision")  
pcapHOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_hopen_offline_with_tstamp_precision")  
pcapActivatePtr = mustLoad("pcap_activate")  
pcapCreatePtr = mustLoad("pcap_create")  
pcapSetSnaplenPtr = mustLoad("pcap_set_snaplen")  
pcapSetPromiscPtr = mustLoad("pcap_set_promisc")  
pcapSetTimeoutPtr = mustLoad("pcap_set_timeout")  
//winpcap does not support rfmon  
pcapCanSetRfmonPtr = mightLoad("pcap_can_set_rfmon")  
pcapSetRfmonPtr = mightLoad("pcap_set_rfmon")  
pcapSetBufferSizePtr = mustLoad("pcap_set_buffer_size")  
//libpcap <1.5 does not have pcap_set_immediate_mode  
pcapSetImmediateModePtr = mightLoad("pcap_set_immediate_mode")  
pcapHopenOfflinePtr = mustLoad("pcap_hopen_offline")  
  
pcapLoaded = true  
return nil  
}

这一段代码是将wpcap代码进行进行绑定的关键
首先导入kernel.dll库

kernel32, err := syscall.LoadLibrary("kernel32.dll")  

然后从kernel.dll中调用AddDllDirectory方法,并以此为判断是使用LoadLibraryEx函数还是LoadLibrary函数来进行wpcap.dll调用
LoadLibraryEx函数相比于LoadLibrary函数多了一个LOAD_LIBRARY_* 标识,来防止dll劫持攻击。
导入wpcap.dll库

wpcapHandle, err = windows.LoadLibraryEx("wpcap.dll", 0,LOAD_LIBRARY_SEARCH_USER_DIRS|LOAD_LIBRARY_SEARCH_SYSTEM32)  

导入了wpcap.dll库后,然后将该动态库的函数都进行了绑定,在文件中它封装了两个load函数如下:

// 必须导入
func mustLoad(fun string) uintptr {  
addr, err := windows.GetProcAddress(wpcapHandle, fun)  
if err != nil {  
panic(fmt.Sprintf("Couldn't load function %s from %s", fun, loadedDllPath))  
}  
return addr  
}  
// 可能导入  
func mightLoad(fun string) uintptr {  
addr, err := windows.GetProcAddress(wpcapHandle, fun)  
if err != nil {  
return 0  
}  
return addr  
}

它导入的函数有以下几种

// It returns an error message string corresponding to error.  
pcapStrerrorPtr = mustLoad("pcap_strerror")  
// get a string for an error or warning status code  
pcapStatustostrPtr = mightLoad("pcap_statustostr") // not available on winpcap  
// get a handle for a live capture  
pcapOpenLivePtr = mustLoad("pcap_open_live")  
//  
pcapOpenOfflinePtr = mustLoad("pcap_open_offline")  
pcapClosePtr = mustLoad("pcap_close")  
pcapGeterrPtr = mustLoad("pcap_geterr")  
pcapStatsPtr = mustLoad("pcap_stats")  
pcapCompilePtr = mustLoad("pcap_compile")  
pcapFreecodePtr = mustLoad("pcap_freecode")  
pcapLookupnetPtr = mustLoad("pcap_lookupnet")  
pcapOfflineFilterPtr = mustLoad("pcap_offline_filter")  
pcapSetfilterPtr = mustLoad("pcap_setfilter")  
pcapListDatalinksPtr = mustLoad("pcap_list_datalinks")  
pcapFreeDatalinksPtr = mustLoad("pcap_free_datalinks")  
pcapDatalinkValToNamePtr = mustLoad("pcap_datalink_val_to_name")  
pcapDatalinkValToDescriptionPtr = mustLoad("pcap_datalink_val_to_description")  
pcapOpenDeadPtr = mustLoad("pcap_open_dead")  
pcapNextExPtr = mustLoad("pcap_next_ex")  
pcapDatalinkPtr = mustLoad("pcap_datalink")  
pcapSetDatalinkPtr = mustLoad("pcap_set_datalink")  
pcapDatalinkNameToValPtr = mustLoad("pcap_datalink_name_to_val")  
pcapLibVersionPtr = mustLoad("pcap_lib_version")  
pcapFreealldevsPtr = mustLoad("pcap_freealldevs")  
pcapFindalldevsPtr = mustLoad("pcap_findalldevs")  
pcapSendpacketPtr = mustLoad("pcap_sendpacket")  
pcapSetdirectionPtr = mustLoad("pcap_setdirection")  
pcapSnapshotPtr = mustLoad("pcap_snapshot")  
//libpcap <1.2 doesn't have pcap_*_tstamp_* functions  
pcapTstampTypeValToNamePtr = mightLoad("pcap_tstamp_type_val_to_name")  
pcapTstampTypeNameToValPtr = mightLoad("pcap_tstamp_type_name_to_val")  
pcapListTstampTypesPtr = mightLoad("pcap_list_tstamp_types")  
pcapFreeTstampTypesPtr = mightLoad("pcap_free_tstamp_types")  
pcapSetTstampTypePtr = mightLoad("pcap_set_tstamp_type")  
pcapGetTstampPrecisionPtr = mightLoad("pcap_get_tstamp_precision")  
pcapSetTstampPrecisionPtr = mightLoad("pcap_set_tstamp_precision")  
pcapOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_open_offline_with_tstamp_precision")  
pcapHOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_hopen_offline_with_tstamp_precision")  
pcapActivatePtr = mustLoad("pcap_activate")  
pcapCreatePtr = mustLoad("pcap_create")  
pcapSetSnaplenPtr = mustLoad("pcap_set_snaplen")  
pcapSetPromiscPtr = mustLoad("pcap_set_promisc")  
pcapSetTimeoutPtr = mustLoad("pcap_set_timeout")  
//winpcap does not support rfmon  
pcapCanSetRfmonPtr = mightLoad("pcap_can_set_rfmon")  
pcapSetRfmonPtr = mightLoad("pcap_set_rfmon")  
pcapSetBufferSizePtr = mustLoad("pcap_set_buffer_size")  
//libpcap <1.5 does not have pcap_set_immediate_mode  
pcapSetImmediateModePtr = mightLoad("pcap_set_immediate_mode")  
pcapHopenOfflinePtr = mustLoad("pcap_hopen_offline")  
//绑定后将pcapLoaded改为true  
pcapLoaded = true  
return nil

整体大致流程:
使用syscall.LoadLibrary先导入kernel.dll库,然后在使用kernel的AddDllDirectory函数做1次判断,然后导入wpcap.dll库并绑定wpcap库函数到go的uintptr变量中,方便下一步的调用。

本集总结:
本集主要介绍了gopacket中对于wpcap.dll这个windows动态链接库进行绑定的方法,使用到了go语言的syscall和golang.org/x/sys/windows两个针对底层系统调用的基础库,在进行绑定的时候首先需要使用syscall.LoadLibrary导入dll,然后使用windows.GetProcAddress获取dll中的函数。

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

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

相关文章

JavaScript DOM之Cookie详解

cookie有的地方习惯使用复数形式的cookies&#xff0c;指的是网站为了识别用户的身份或者进行一些必要数据的缓存而使用的技术&#xff0c;它的数据是存在用户的终端上&#xff0c;也就是在浏览器上的。 一、什么是cookie 随着互联网的不断发展各种基于互联网的服务系统逐渐多…

3D点云数据的标定,从搭建环境到点云标定方法及过程,只要有一台Windows笔记本,让你学会点云标定

ptscloudpre: 点云标定准备&#xff1a; 说明&#xff1a; 如下介绍适用windows系统的电脑。apple笔记本同理&#xff0c;但是需要安装MAC版本的anaconda。网址&#xff1a;Free Download | Anaconda可下载对应MAC版本的Anaconda的安装包建议下载2022年或2021年的安装包安装。…

nginx限制ip访问

先看一下被禁止的效果 如何配置 禁止访问的话直接在location模块增加类似如下配置 deny all; 完整示例 location / {deny all;root html;index index.html index.htm;} 默认是allow all就是允许所有ip访问,如果只配置指定ip可以访问是无效的,还是所有的ip可以访问 无效示例…

【UAT阶段】测试计划分享

前面我有分享UAT阶段注意事项&#xff0c;今天跟大家分享UAT测试计划包含哪些内容&#xff1a; 希望该计划能给大家在实际项目中有所帮助&#xff1b;

k8s图形化管理工具之rancher

前言 在前面的k8s基础学习中,我们学习了各种资源的搭配运用,以及命令行,声明式文件创建。这些都是为了k8s管理员体会k8s的框架,内容基础。在真正的生产环境中,大部分的公司还是会选用图形化管理工具来管理k8s集群,大大提高工作效率。 在二进制搭建k8集群时,我们就知道了…

java web 研究生信息管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web研究生信息管理系统是一套完善的java web信息管理系统 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境 为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为My…

【MySQL故障】主从延迟越来越大

问题背景 研发执行了一个批量更新数据的操作&#xff0c;操作的表是个宽表&#xff0c;大概有90多个字段&#xff0c;数据量有800多w&#xff0c;但是研发是根据ID按行更新。更新开始后&#xff0c;该集群的主从延迟越来越大。 问题现象 1 从库应用binlog基本无落后&#xf…

【腾讯云服务器】幻兽帕鲁私服服务器部署保姆级教程

在帕鲁的世界&#xff0c;你可以选择与神奇的生物「帕鲁」一同享受悠闲的生活&#xff0c;也可以投身于与偷猎者进行生死搏斗的冒险。帕鲁可以进行战斗、繁殖、协助你做农活&#xff0c;也可以为你在工厂工作。你也可以将它们进行售卖&#xff0c;或分解后食用。 想要部署属于自…

IDEA常用插件(本人常用,不全)

文章目录 一、图标提示类插件1、Lombok插件&#xff08;用户配合lombok依赖的工具&#xff09;2、MybatisX插件3、GitToolBox4、VUE.js5、ESLint 二、代码自动生成插件1、EasyCode插件&#xff1a;自动生成代码神器2、GsonFormat 三、常用工具类1、IDE Eval Reset 插件&#xf…

解读Android进程优先级ADJ算法

本文基于原生Android 9.0源码来解读进程优先级原理,基于篇幅考虑会精炼部分代码 一、概述 1.1 进程 Android框架对进程创建与管理进行了封装,对于APP开发者只需知道Android四大组件的使用。当Activity, Service, ContentProvider, BroadcastReceiver任一组件启动时,当其所…

python小项目:口令保管箱

代码&#xff1a; #! python3 # python 编程-----口令保管箱passwords{emails: F7minlBDDuvMJuxESSKHFhTxFtjVB6,blog:VmALvQyKAxiVH5G8v01if1MLZF3sdt,luggage:12345,} import sys,pyperclip if len(sys.argv)<2:print(usage:python python3文件[accout]-copy accout pass…

大模型学习笔记一:大模型应用开发基础

文章目录 一、大模型一些概念介绍 一、大模型一些概念介绍 1&#xff09;产品和大模型的区别&#xff08;产品通过调用大模型来具备的能力&#xff09; 2&#xff09;AGI定义 概念&#xff1a;一切问题可以用AI解决 3&#xff09;大模型通俗原理 根据上文&#xff0c;猜测下…

100.乐理基础-五线谱-是否需要学习五线谱

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;99.乐理基础-简谱的多声部-CSDN博客 简谱与五线谱的区别&#xff0c;各自的优劣势、使用场景、范围等&#xff1a; 要搞懂这个问题&#xff0c;其实核心就是四个词&#xff1a;首调、固定调、单声部、多声部 首调、…

github ssh ssh-keygen

生成和使用 SSH 密钥对是一种安全的身份验证方式&#xff0c;用于在你的本地系统和 GitHub 之间进行身份验证。以下是在 GitHub 上生成和使用 SSH 密钥对的基本步骤&#xff1a; 1. 生成 SSH 密钥对 在命令行中执行以下命令来生成 SSH 密钥对&#xff1a; ssh-keygen -C &q…

计算机速成课Crash Course - 23. 屏幕 2D 图形显示

今天继续计算机速成课Crash Course的系列讲解。 更多技术文章&#xff0c;全网首发公众号 “摸鱼IT” 锁定 -上午11点 - &#xff0c;感谢大家关注、转发、点赞&#xff01; 计算机速成课Crash Course - 23. 屏幕& 2D 图形显示 (qq.com) 23. 屏幕& 2D 图形显示 这台…

YOLOv5改进系列(28)——添加DSConv注意力卷积(ICCV 2023|用于管状结构分割的动态蛇形卷积)

【YOLOv5改进系列】前期回顾: YOLOv5改进系列(0)——重要性能指标与训练结果评价及分析 YOLOv5改进系列(1)——添加SE注意力机制

06.Elasticsearch应用(六)

Elasticsearch应用&#xff08;六&#xff09; 1.什么是分词器 ES文档的数据拆分成一个个有完整含义的关键词&#xff0c;并将关键词与文档对应&#xff0c;这样就可以通过关键词查询文档。要想正确的分词&#xff0c;需要选择合适的分词器 2.ES中的默认分词器 fingerprint…

软件游戏提示msvcp140.dll丢失的解决方法,全面分析msvcp140.dll文件

msvcp140.dll是Microsoft Visual C 2015 Redistributable的一部分&#xff0c;它包含了许多用于运行程序的函数和类库。当这个文件丢失或损坏时&#xff0c;依赖于该组件的应用程序可能无法正常启动&#xff0c;系统会弹出错误提示&#xff0c;告知用户找不到msvcp140.dll文件。…

【寒假打卡】Day02

文章目录 选择编程NC31 第一个只出现一次的字符面试题 01.01. 判定字符是否唯一 选择 以下程序运行后的输出结果是&#xff08; &#xff09; #include <stdio.h> void fun(char **p) { int i; for(i 0; i < 4; i) printf("%s", p[i]); } in t main() { …

河南嘉家购商贸有限公司获绿色积分信用认证

“实现绿色产业、打造完善的绿色产业链、走可持续发展共创共赢”。近日&#xff0c;河南嘉家购商贸有限公司获得绿色积分认证&#xff0c;确认了该企业在绿色消费积分领域的领先地位。 据了解&#xff0c;河南嘉家购商贸有限公司始终将绿色积分视为企业发展的核心要素。全面优化…