Golang跨平台获取DLL文件版本和产品版本信息的方法

Golang跨平台获取DLL文件版本和产品版本信息的方法

package main

import (
"fmt"
"io/ioutil"
"log"
"bytes"
"os"
)

func main() {
	content, err := ioutil.ReadFile("F:/tesdll/Microsoft.AspNetCore.Authentication.Abstractions.dll")
	if err != nil {
		log.Fatal(err)
	}
}

通过读取 DLL 信息,我应该能够获取 DLL 文件版本和产品版本。 这应该在 Windows 和 Linux 系统上无缝运行。

提前感谢


更多关于Golang跨平台获取DLL文件版本和产品版本信息的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

我的代码将在Linux机器上运行,但正在读取dll文件…

更多关于Golang跨平台获取DLL文件版本和产品版本信息的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


您可以检查内容中该信息所在的位置。 每个DLL内部都包含一个称为StringFileInfo的特殊信息,然后搜索诸如ProductVersion和FileVersion之类的标签。

在这种情况下,我指的是动态加载的库(作为 .so 文件)

Selvin_Thangadurai:

应该在Windows和Linux上无缝运行。

Linux不使用DLL…

非常感谢 Yamil_Bracho

以下是跨平台获取DLL文件版本和产品版本信息的方法。可以使用debug/pe包解析Windows PE文件格式,这在Windows和Linux上都能正常工作:

package main

import (
    "debug/pe"
    "encoding/binary"
    "fmt"
    "log"
    "os"
    "strings"
)

// VS_VERSION_INFO结构体
type VS_VERSION_INFO struct {
    Length      uint16
    ValueLength uint16
    Type        uint16
    Key         [16]uint16
}

// StringFileInfo结构体
type StringFileInfo struct {
    Length      uint16
    ValueLength uint16
    Type        uint16
    Key         [16]uint16
    Padding     uint16
    Children    []StringTable
}

// StringTable结构体
type StringTable struct {
    Length      uint16
    ValueLength uint16
    Type        uint16
    Key         [16]uint16
    Padding     uint16
    Children    []String
}

// String结构体
type String struct {
    Length      uint16
    ValueLength uint16
    Type        uint16
    Key         []uint16
    Padding     uint16
    Value       []uint16
}

func main() {
    if len(os.Args) < 2 {
        fmt.Println("Usage: go run main.go <dll_file>")
        return
    }

    filePath := os.Args[1]
    versionInfo, err := getDLLVersionInfo(filePath)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("文件版本: %s\n", versionInfo["FileVersion"])
    fmt.Printf("产品版本: %s\n", versionInfo["ProductVersion"])
    fmt.Printf("产品名称: %s\n", versionInfo["ProductName"])
    fmt.Printf("文件描述: %s\n", versionInfo["FileDescription"])
    fmt.Printf("公司名称: %s\n", versionInfo["CompanyName"])
}

func getDLLVersionInfo(filePath string) (map[string]string, error) {
    file, err := pe.Open(filePath)
    if err != nil {
        return nil, fmt.Errorf("打开PE文件失败: %v", err)
    }
    defer file.Close()

    // 查找.rsrc段
    var rsrcSection *pe.Section
    for _, section := range file.Sections {
        if section.Name == ".rsrc\x00\x00\x00" {
            rsrcSection = section
            break
        }
    }

    if rsrcSection == nil {
        return nil, fmt.Errorf("未找到.rsrc段")
    }

    // 读取.rsrc段数据
    rsrcData := make([]byte, rsrcSection.Size)
    _, err = file.Seek(int64(rsrcSection.Offset), 0)
    if err != nil {
        return nil, fmt.Errorf("读取.rsrc段失败: %v", err)
    }

    _, err = file.File.Read(rsrcData)
    if err != nil {
        return nil, fmt.Errorf("读取.rsrc数据失败: %v", err)
    }

    // 查找版本信息资源
    versionInfo, err := findVersionInfo(rsrcData)
    if err != nil {
        return nil, err
    }

    return parseVersionInfo(versionInfo)
}

func findVersionInfo(rsrcData []byte) ([]byte, error) {
    // 简化的版本信息查找逻辑
    // 在实际应用中需要完整解析资源目录结构
    vsVersionInfoSignature := []byte("VS_VERSION_INFO")
    
    for i := 0; i < len(rsrcData)-len(vsVersionInfoSignature); i++ {
        if bytes.Equal(rsrcData[i:i+len(vsVersionInfoSignature)], vsVersionInfoSignature) {
            // 找到版本信息块,返回整个块
            start := i - 6 // VS_VERSION_INFO结构体开始位置
            if start < 0 {
                start = 0
            }
            
            // 读取块长度
            if start+2 > len(rsrcData) {
                return nil, fmt.Errorf("无效的版本信息块")
            }
            
            length := binary.LittleEndian.Uint16(rsrcData[start:])
            if start+int(length) > len(rsrcData) {
                return nil, fmt.Errorf("版本信息块长度超出范围")
            }
            
            return rsrcData[start : start+int(length)], nil
        }
    }
    
    return nil, fmt.Errorf("未找到版本信息")
}

func parseVersionInfo(data []byte) (map[string]string, error) {
    result := make(map[string]string)
    
    if len(data) < 6 {
        return nil, fmt.Errorf("版本信息数据过短")
    }

    // 解析VS_VERSION_INFO
    var vs VS_VERSION_INFO
    vs.Length = binary.LittleEndian.Uint16(data[0:])
    vs.ValueLength = binary.LittleEndian.Uint16(data[2:])
    vs.Type = binary.LittleEndian.Uint16(data[4:])
    
    // 查找StringFileInfo
    stringFileInfoPos := 6 + 32 // VS_VERSION_INFO头部 + Key
    if stringFileInfoPos+4 > len(data) {
        return nil, fmt.Errorf("StringFileInfo位置超出范围")
    }

    // 简化的字符串解析
    // 在实际应用中需要完整解析StringFileInfo和StringTable结构
    content := string(data)
    
    // 查找常见的版本信息字段
    fields := []string{
        "FileVersion",
        "ProductVersion", 
        "ProductName",
        "FileDescription",
        "CompanyName",
    }
    
    for _, field := range fields {
        if value := extractStringValue(content, field); value != "" {
            result[field] = value
        }
    }
    
    return result, nil
}

func extractStringValue(content, field string) string {
    prefix := field + "\x00"
    start := strings.Index(content, prefix)
    if start == -1 {
        return ""
    }
    
    valueStart := start + len(prefix)
    end := strings.Index(content[valueStart:], "\x00")
    if end == -1 {
        return ""
    }
    
    return strings.TrimSpace(content[valueStart : valueStart+end])
}

// 辅助函数:比较字节切片
func bytes.Equal(a, b []byte) bool {
    if len(a) != len(b) {
        return false
    }
    for i := range a {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}

使用方法:

go run main.go Microsoft.AspNetCore.Authentication.Abstractions.dll

这个实现:

  1. 使用debug/pe包解析PE文件格式
  2. 查找.rsrc资源段中的版本信息
  3. 解析VS_VERSION_INFO结构获取版本数据
  4. 在Windows和Linux上都能运行

注意:这是一个简化版本,完整的版本信息解析需要处理PE文件资源目录的完整结构。对于生产环境,建议使用更成熟的第三方库如github.com/josephspurrier/goversioninfo

回到顶部