网络安全【免费下载链接】sliverAdversary Emulation Framework项目地址https://gitcode.com/gh_mirrors/sl/sliver点击查看免费下载shm是一个以纯 Go 实现 System V 共享内存函数shmget、shmat、shmdt、shmctl的开源库本仓库在implant/vendor/github.com/gen2brain/shm下将其作为 vendor 依赖引入并通过kbinani/screenshot的 X11 抓屏链路实际调用。阅读本文后你将掌握共享内存段从创建、附加、读写到释放的完整生命周期理解每个标志位与控制命令的底层语义并能基于本仓库源码写出生效的 Go 共享内存程序。System V 共享内存是什么System V 共享内存System V shared memory是 POSIX 之外的经典 UNIX IPC 机制之一内核维护一段可以被多个进程同时映射进各自地址空间的物理内存区域进程通过一个整型标识符shmId而不是管道或套接字来访问它。相比消息队列和信号量共享内存是吞吐量最高、零拷贝的进程间通信方式——数据写入后其他进程立即可见无需经过内核复制。在 C 语言生态中这套机制由sys/shm.h提供四个核心函数函数作用shmget()创建或获取一个共享内存段的标识符shmat()把共享内存段附加映射到当前进程地址空间shmdt()将共享内存段从当前进程地址空间分离shmctl()对共享内存段执行控制操作删除、查询状态、加锁等本仓库中的gen2brain/shm库就是用 Go 重新封装这四个系统调用的实现入口见 shm.go。安装与导入原文档给出的安装方式与标准 Go 模块一致go get -u github.com/gen2brain/shm在本仓库中该依赖位于implant/vendor/目录下属于植入体implant编译链的 vendor 依赖因此无需单独下载即可直接导入import github.com/gen2brain/shm纯 Go 与 cgo 的分界原文档特别说明除 Solaris 之外整个库都以纯 Go 实现不依赖 cgo。之所以 Solaris 例外是因为 Go 官方问题 golang/go#24357 所涉及的 Solaris 平台系统调用 ABI 问题导致无法直接用syscall包完成调用。这一点在源码中得到印证以 Linux/amd64 为代表的平台文件如 shm_linux_amd64.go直接引用syscall.SYS_SHMAT、syscall.SYS_SHMCTL、syscall.SYS_SHMDT、syscall.SYS_SHMGET这四个标准系统调用号而 shm_solaris.go 顶部带有// build solaris构建标签并直接通过#include sys/ipc.h、#include sys/shm.h调用 C 函数C.shmget、C.shmat、C.shmdt、C.shmctl这是唯一走 cgo 的路径。此外文件头部// build darwin dragonfly freebsd linux netbsd openbsd的构建约束说明在其余主流 UNIX 系平台上库均走syscall纯 Go 路径。每个平台还各自定义了sysShmAt等系统调用号常量例如 shm_freebsd.go 中 FreeBSD 的sysShmGet 231、sysShmAt 228而 shm_linux_386.go 中 386 架构的sysShmGet 29、sysShmAt 30shm_linux_arm.go 中 ARM 的sysShmGet 23、sysShmAt 21——这些硬编码常量正是纯 Go 实现跨架构可移植性的关键。核心 API 全解析shm包对外暴露五个函数对应 C 语言的四个系统调用并额外提供了常用便捷封装。以下 API 签名均出自 shm.go。Get创建/获取共享内存段func Get(key int, size int, shmFlg int) (shmId int, err error)Get返回与key关联的共享内存段标识符。创建新段的规则与 POSIX 语义一致若key取值为IPC_PRIVATE0内核总是创建一个全新的、不与他人共享的私有段若key非私有且不存在对应段、同时在shmFlg中指定了IPC_CREAT则创建新段若shmFlg同时指定IPC_CREAT和IPC_EXCL而该key对应的段已存在则调用失败errno 为EEXIST源码注释中明确写明了这一行为。size表示段大小字节shmFlg是权限位与模式位的组合。底层实现通过syscall.Syscall(sysShmGet, ...)完成返回-1时把 errno 作为 error 返回。At附加共享内存段func At(shmId int, shmAddr uintptr, shmFlg int) (data []byte, err error)At把shmId标识的段附加到当前进程地址空间。shmAddr传0NULL时由内核自动选择附加地址——源码注释强调这是“首选的可移植做法”。shmFlg可取SHM_RDONLY只读附加、SHM_RND地址按 SHMLBA 取整等标志。值得注意的实现细节附加成功后At内部会先调用Size(shmId)查询段长度然后通过unsafe构造一个覆盖该段内存的[]byte切片addr/len/cap三者均由共享内存地址和长度填充返回给调用者。也就是说调用方拿到的data切片直接映射了共享内存对data的读写就是对共享内存的读写无需额外拷贝。Dt分离共享内存段func Dt(data []byte) errorDt将之前由At附加的段从当前进程地址空间分离。分离时传入的必须是At返回的那个切片底层通过syscall.Syscall(sysShmDt, uintptr(unsafe.Pointer(data[0])), ...)以切片首地址作为分离地址。Ctl / Rm / Size控制与查询func Ctl(shmId int, cmd int, buf *IdDs) (int, error) func Rm(shmId int) error func Size(shmId int) (int64, error)Ctl是通用控制入口cmd取值见下方“控制命令”一节buf指向IdDs结构体查询状态时的结果缓冲区Rm是Ctl(shmId, IPC_RMID, nil)的便捷封装用于标记删除共享内存段Size通过Ctl(shmId, IPC_STAT, idDs)获取段状态并返回其中的SegSz字段段大小字节。标志位与控制命令速查源码中定义了一组与 POSIX 常量等值的常量是编写共享内存程序时最常用的参数shmget模式位shmFlg用常量值八进制含义IPC_CREAT01000key 不存在时创建新段IPC_EXCL02000key 已存在时失败配合IPC_CREAT使用IPC_NOWAIT04000等待时直接返回错误不阻塞特殊 key 值常量值含义IPC_PRIVATE0私有段不与其他 key 关联shmat标志shmFlg用常量值八进制含义SHM_RDONLY010000只读附加SHM_RND020000将附加地址按 SHMLBA 取整SHM_REMAP040000附加时接管已有映射区域SHM_EXEC0100000允许执行访问shmctl命令cmd用常量值含义IPC_RMID0删除段标识符标记删除IPC_SET1设置ipc_perm权限选项IPC_STAT2读取ipc_perm等状态到IdDsSHM_LOCK1锁定段仅 rootSHM_UNLOCK12解锁段仅 root注意两点易混淆之处一是IPC_SET/IPC_STAT/IPC_RMID在 Linux 上取值 0/1/2而在 Solaris 上取值 10/11/12见 shm_solaris.go 中IPC_RMID 10库内部已按平台分别定义调用方无需关心差异二是SHM_LOCK与IPC_SET数值相同均为 1但二者分别用于锁定与权限设置属于不同的命令域实际使用中不会混淆。数据结构Perm 与 IdDs控制操作依赖两个关键结构体定义在 shm_linux_amd64.go 中其他平台文件有按 ABI 差异调整的版本。Perm描述段的权限信息与内核ipc_perm对应type Perm struct { Key int32 // key Uid uint32 // 属主用户 ID Gid uint32 // 属主组 ID Cuid uint32 // 创建者用户 ID Cgid uint32 // 创建者组 ID Mode uint16 // 读写权限位 Seq uint16 // 序列号 // 之后是各平台的对齐与保留字段 }IdDs描述整个共享内存段的状态Size正是读取其SegSz字段type IdDs struct { Perm Perm // 权限结构 SegSz uint64 // 段大小字节 Atime int64 // 最近一次附加时间 Dtime int64 // 最近一次分离时间 Ctime int64 // 最近一次变更时间 Cpid int32 // 创建者 PID Lpid int32 // 最近一次 shmat/shmdt 的 PID Nattch uint64 // 当前附加计数 // 其余为保留字段 }这些时间戳与附加计数字段让IPC_STAT可以用于监控段的使用状态例如判断是否仍被其他进程占用后再决定是否IPC_RMID。完整示例父子进程共享内存结合上述 API 与标志位一个典型的共享内存使用流程如下流程与 shm.go 中 Get→At→读写→Dt→Rm 的生命周期一致package main import ( fmt os syscall github.com/gen2brain/shm ) func main() { const size 4096 // 1. 创建私有共享内存段权限 0666 id, err : shm.Get(shm.IPC_PRIVATE, size, shm.IPC_CREAT|0666) if err ! nil { panic(err) } defer shm.Rm(id) // 5. 删除段标记删除 // 2. 附加到当前进程 data, err : shm.At(id, 0, 0) if err ! nil { panic(err) } defer shm.Dt(data) // 4. 分离 pid, _, _ : syscall.Syscall(syscall.SYS_FORK, 0, 0, 0) if pid 0 { // 子进程写入 copy(data, []byte(hello from child)) os.Exit(0) } // 父进程等待子进程写完后读取 syscall.Wait4(int(pid), nil, 0, nil) fmt.Println(string(data[:len(hello from child)])) }要点shm.Get(shm.IPC_PRIVATE, ...)创建私有段IPC_CREAT|0666表示不存在则创建且权限为读写shm.At(id, 0, 0)让内核自动选择附加地址返回的data切片直接对应共享内存defer shm.Rm(id)删除段、defer shm.Dt(data)分离段保证资源释放由于 Linux 的fork后子进程继承父进程地址空间映射父子进程天然共享该段在真正跨进程场景下则需要约定一个非零 key如ftok生成的 key供多方Get同一段。在本仓库中的实际应用X11 截屏的零拷贝路径gen2brain/shm在本仓库并非孤立依赖它支撑着 Linux 图形环境下的屏幕捕获功能。调用链位于 xwindow.gokbinani/screenshot库的 X11 后端服务于植入体的截图能力通过xgb连接 X server并尝试初始化 MIT-SHM 扩展mshm.Init若失败则回退到xproto.GetImage的普通路径useShm false成功时计算截屏区域大小shmSize : intersect.Dx() * intersect.Dy() * 4RGBA 每像素 4 字节调用shm.Get(shm.IPC_PRIVATE, shmSize, shm.IPC_CREAT|0777)创建共享内存段调用shm.At(shmId, 0, 0)附加得到data切片并将其 shmId 交给mshm.Attach/mshm.GetImage让 X server 把像素数据直接写入共享内存处理完毕后通过defer shm.Rm(shmId)与defer shm.Dt(data)成对清理段与映射。这段代码完整示范了本库的典型用法IPC_PRIVATE IPC_CREAT 创建 → At 附加 → 使用 → Rm Dt 清理并且体现了共享内存“让内核外设直接写入用户内存、避免两次拷贝”的性能优势——这正是截屏这类高频、大数据量场景选择共享内存的原因。关联参考核心实现shm.goLinux amd64 常量与结构体shm_linux_amd64.go各架构系统调用号386 见 shm_linux_386.goARM 见 shm_linux_arm.gocgo 平台实现Solarisshm_solaris.go库内实际调用方X11 截屏xwindow.go许可证与作者信息见同目录 LICENSE 与 AUTHORS如果你需要处理 System V 消息队列类 IPCmsgctl、msgget、msgrcv、msgsnd原文档指向了配套的siadat/ipc库可作为同一 IPC 技术族的扩展阅读。赞分享网络安全【免费下载链接】sliverAdversary Emulation Framework项目地址https://gitcode.com/gh_mirrors/sl/sliver点击查看免费下载相关推荐Sway 合约如何用 CEI 模式防范重入攻击Sway 合约如何用 CEI 模式防范重入攻击 Sway 合约在调用外部合约时存在被重入的风险合约 A 调用合约 B 后B 又回调 A从而在状态尚未更新网络安全OpenCloud 依赖剖析go-shm 纯 Go 跨平台 POSIX 共享内存库实现解读OpenCloud 依赖剖析go shm 纯 Go 跨平台 POSIX 共享内存库实现解读 在 OpenCloud 的依赖体系中 github.com/ko后端微服务存储认证鉴权深入解析 go-sqlite纯 Go 实现的 SQLite 驱动与 Sliver 中的实践应用深入解析 go sqlite纯 Go 实现的 SQLite 驱动与 Sliver 中的实践应用 go sqlite 是一个纯 Go 编写的 SQLite 数据网络安全创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
