// golang 實現(xiàn)讀取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]}) // 讀取從當(dāng)前位置移位到 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) }成都創(chuàng)新互聯(lián)公司是創(chuàng)新、創(chuàng)意、研發(fā)型一體的綜合型網(wǎng)站建設(shè)公司,自成立以來公司不斷探索創(chuàng)新,始終堅持為客戶提供滿意周到的服務(wù),在本地打下了良好的口碑,在過去的十載時間我們累計服務(wù)了上千家以及全國政企客戶,如成都主動防護網(wǎng)等企業(yè)單位,完善的項目管理流程,嚴(yán)格把控項目進度與質(zhì)量監(jiān)控加上過硬的技術(shù)實力獲得客戶的一致贊賞。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。