golang 获取exe、dll、apk 版本号

// golang 实现读取exe dll apk 版本号
package main

import (
    "flag"
    "fmt"
    "log"
    "os"
    "path/filepath"
)

import (
    "github.com/lunny/axmlParser"
)

var (
    file fileInfo
)

const (
    MZ       = "MZ"
    PE       = "PE"
    RSRC     = ".rsrc"
    TYPET    = 16
    PEOFFSET = 64
    MACHINE  = 332
    DEFAULT  = `C:\Windows\System32\cmd.exe`
)

type fileInfo struct {
    FilePath string
    Version  string
    Debug    bool
}

func (f *fileInfo) checkError(err error) {
    if err != nil {
        log.Fatalln(err)
    }
}

// 获取exe dll版本
func (f *fileInfo) GetExeVersion() (err error) {
    file, err := os.Open(f.FilePath)
    f.checkError(err)

    // 第一次读取64 byte
    buffer := make([]byte, 64)
    _, err = file.Read(buffer)
    f.checkError(err)
    defer file.Close()

    str := string(buffer[0]) + string(buffer[1])
    if str != MZ {
        log.Fatalln("读取exe错误,找不到 MZ.", f.FilePath)
    }

    peOffset := f.unpack([]byte{buffer[60], buffer[61], buffer[62], buffer[63]})
    if peOffset < PEOFFSET {
        log.Fatalln("peOffset 读取错误.", f.FilePath)
    }

    // 读取从文件开头移位到 peOffset,第二次读取 24 byte
    _, err = file.Seek(int64(peOffset), 0)
    buffer = make([]byte, 24)
    _, err = file.Read(buffer)
    f.checkError(err)

    str = string(buffer[0]) + string(buffer[1])
    if str != PE {
        log.Fatalln("读取exe错误,找不到 PE.", f.FilePath)
    }

    machine := f.unpack([]byte{buffer[4], buffer[5]})
    if machine != MACHINE {
        log.Fatalln("machine 读取错误.", f.FilePath)
    }

    noSections := f.unpack([]byte{buffer[6], buffer[7]})
    optHdrSize := f.unpack([]byte{buffer[20], buffer[21]})

    // 读取从当前位置移位到 optHdrSize,第三次读取 40 byte
    file.Seek(int64(optHdrSize), 1)
    resFound := false
    for i := 0; i < int(noSections); i++ {
        buffer = make([]byte, 40)
        file.Read(buffer)
        str = string(buffer[0]) + string(buffer[1]) + string(buffer[2]) + string(buffer[3]) + string(buffer[4])
        if str == RSRC {
            resFound = true
            break
        }
    }
    if !resFound {
        log.Fatalln("读取exe错误,找不到 .rsrc.", f.FilePath)
    }

    infoVirt := f.unpack([]byte{buffer[12], buffer[13], buffer[14], buffer[15]})
    infoSize := f.unpack([]byte{buffer[16], buffer[17], buffer[18], buffer[19]})
    infoOff := f.unpack([]byte{buffer[20], buffer[21], buffer[22], buffer[23]})

    // 读取从文件开头位置移位到 infoOff,第四次读取 infoSize byte
    file.Seek(int64(infoOff), 0)
    buffer = make([]byte, infoSize)
    _, err = file.Read(buffer)
    f.checkError(err)

    nameEntries := f.unpack([]byte{buffer[12], buffer[13]})
    idEntries := f.unpack([]byte{buffer[14], buffer[15]})

    var infoFound bool
    var subOff, i int64
    for i = 0; i < (nameEntries + idEntries); i++ {
        typeT := f.unpack([]byte{buffer[i*8+16], buffer[i*8+17], buffer[i*8+18], buffer[i*8+19]})
        if typeT == TYPET {
            infoFound = true
            subOff = int64(f.unpack([]byte{buffer[i*8+20], buffer[i*8+21], buffer[i*8+22], buffer[i*8+23]}))
            break
        }
    }
    if !infoFound {
        log.Fatalln("读取exe错误,找不到 typeT == 16.", f.FilePath)
    }

    subOff = subOff & 0x7fffffff
    infoOff = f.unpack([]byte{buffer[subOff+20], buffer[subOff+21], buffer[subOff+22], buffer[subOff+23]}) //offset of first FILEINFO
    infoOff = infoOff & 0x7fffffff
    infoOff = f.unpack([]byte{buffer[infoOff+20], buffer[infoOff+21], buffer[infoOff+22], buffer[infoOff+23]}) //offset to data
    dataOff := f.unpack([]byte{buffer[infoOff], buffer[infoOff+1], buffer[infoOff+2], buffer[infoOff+3]})
    dataOff = dataOff - infoVirt

    version1 := f.unpack([]byte{buffer[dataOff+48], buffer[dataOff+48+1]})
    version2 := f.unpack([]byte{buffer[dataOff+48+2], buffer[dataOff+48+3]})
    version3 := f.unpack([]byte{buffer[dataOff+48+4], buffer[dataOff+48+5]})
    version4 := f.unpack([]byte{buffer[dataOff+48+6], buffer[dataOff+48+7]})

    version := fmt.Sprintf("%d.%d.%d.%d", version2, version1, version4, version3)
    f.Version = version

    return nil
}

func (f *fileInfo) unpack(b []byte) (num int64) {
    for i := 0; i < len(b); i++ {
        num = 256*num + int64((b[len(b)-1-i] & 0xff))
    }
    return
}

// 获取 apk 版本
func (f *fileInfo) GetApkVersion() (err error) {
    listener := new(axmlParser.AppNameListener)
    _, err = axmlParser.ParseApk(f.FilePath, listener)
    f.checkError(err)

    f.Version = listener.VersionName
    return nil
}

func init() {
    flag.StringVar(&file.FilePath, "path", DEFAULT, "Get exe or dll or apk version information.")
    flag.BoolVar(&file.Debug, "d", false, "if true print exe or dll file name.")
}

func main() {
    flag.Parse()

    suffix := filepath.Ext(file.FilePath)
    switch suffix {
    case ".exe", ".dll":
        file.GetExeVersion()
    case ".apk":
        file.GetApkVersion()
    default:
        log.Fatalln("仅能获取exe、dll、apk版本号,请重新输入程序路径.", file.FilePath)
    }

    switch {
    case file.Debug:
        fmt.Printf("%s 的版本号为: ", file.FilePath)
    case file.FilePath == DEFAULT:
        flag.PrintDefaults()
        fmt.Printf("%s 的版本号为: ", file.FilePath)
    }

    fmt.Printf("%s", file.Version)
}
时间: 2024-10-18 12:07:21

golang 获取exe、dll、apk 版本号的相关文章

calling c++ from golang with swig--windows dll (四)

calling c++ from golang with swig--windows dll 四 前面讲述了windows环境下golang如何通过swig调用C++ dll.由于编译c++代码使用了gcc,需要为DLL文件增加按照g++ name mangling的导出项.如果DLL导出了大量函数.类或变量,为DLL编写def文件是一项非常麻烦.无聊的事情.如果golang能够利用visual c++编译器来编译c++代码的话,或许不需要额外的def文件了,但是我用百度和谷歌浏览器进行了大量的

calling c++ from golang with swig--windows dll (三)

calling c++ from golang with swig--windows dll 三 使用动态链接库(DLL)主要有两种方式:一种通过链接导入库,在代码中直接调用DLL中的函数:另一种借助LoadLibrary/LoadLibraryEx,GetProcessAddress函数在代码中间接调用DLL中的函数.这两种使用方式对应两种动态链接,分别称为: load-time dynamic link (加载时动态链接)和run-time dynamic link (运行时动态链接). D

GetModuleHandle(NULL)获取当前DLL模块基址?

做一项目想在DLL内部代码实现获取本DLL的模块基址,而且不知道本DLL名称 最简单的方法是想到GetModuleHandle(NULL),是否可以呢? 参看http://blog.csdn.net/guzhou_diaoke/article/details/8826558到的答案是否 自己尝试了一下: DLL代码(testDll): BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv

Android 获取当前应用的版本号和当前系统的版本号

1.获取当前程序版本名 我们可以在AndroidManifest.xml中设置程序的版本号等,如android:versionName="1.0",那如果想在代码中获取这个版本号呢,可以用如下方法(这些修改版本号时只需要修改AndroidManifest.xml中的设置,不用修改代码了): /** * 返回当前程序版本名 */ public static String getAppVersionName(Context context) { String versionName = &

获取应用的当前版本号&amp;获取当前android系统的版本号

获取当前应用的版本号: private String getVersionName() throws Exception { // 获取packagemanager的实例 PackageManager packageManager = getPackageManager(); // getPackageName()是你当前类的包名,0代表是获取版本信息 PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(),0)

JS获取浏览器类型和版本号

JS获取浏览器类型和版本号,增加了IE11的判断. var zbrowser = {} var ua = navigator.userAgent.toLowerCase(); var isMoreThanIE10 = !(/msie/.test(ua)) && ua.match(/trident/); if (isMoreThanIE10) { zbrowser.msie = true; zbrowser.firefox = false; zbrowser.chrome = false;

Delphi2010如何获取程序内部自身版本号?

用原来的GetFileVersionInfo只能获取Delpi7的程序版本号,用在Delphi2010中就不管用了 //------ 获取文件版本号 function F_GetFileVersion(FN: string): string; var Temp, InfoSize: Cardinal; FileData: Pointer; FileInfo: PVSFixedFileInfo; begin Result := ''; if not FileExists(FN) then Exit

获取安卓应用的版本号

在清单文件AndroidManifest.xml中设置程序的版本号:android:versionName="1.0.1", 有时候我们需要在代码中获取到这个版本号. 1.获取当前应用的版本名: public static String getAppVersionName(Context context) { String versionName = ""; try { // 获取packagemanager的实例 PackageManager packageMan

如何获取 当前系统的 版本号?

//获取当前系统功能的版本号 int currentPhoneVersionCode = android.os.Build.VERSION.SDK_INT; MyApplication.currentPhoneVersionCode = currentPhoneVersionCode; LogUtil.d(TAG, "----------当前的版本号:" + MyApplication.currentPhoneVersionCode);