Go中二进制与十六进制值匹配问题:SanCov解析器开发
问题分析与解决方案
首先,你遇到的核心问题有两个:
- 类型不匹配:Go 中
[]byte切片不能直接和整数常量(比如0xC0BFFFFFFFFFFF64)比较,这两种类型不属于同一类别,编译器必然会报错。 - 字节序(端序)问题:从你的输出
value: 64ffffffffffbfc0能看出,文件里的魔法值是按小端序存储的,而你写的0xC0BFFFFFFFFFFF64是大端序的十六进制表示,直接对比数值也会出错。
接下来给你两种可行的解决方法:
方法一:直接对比字节切片内容
既然魔法值是固定的8字节,我们可以直接构造对应的字节数组(和文件里存储的顺序一致)来对比。从你的输出可知,64位魔法值在文件里的字节序列是0x64, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc0,32位则是0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc0。
修改后的代码如下:
package main import ( "bytes" "fmt" "log" "os" ) func main() { path := "test.exe.16900.sancov" f, err := os.Open(path) if err != nil { log.Fatal("Error while opening file", err) } defer f.Close() // 记得关闭文件,避免资源泄漏 // 定义两种魔法值的字节序列(小端序) magic64 := []byte{0x64, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc0} magic32 := []byte{0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc0} data := make([]byte, 8) bytesread, err := f.Read(data) if err != nil { log.Fatal("Error reading magic bytes:", err) } if bytesread != 8 { log.Fatal("Expected 8 bytes for magic header, got", bytesread) } fmt.Printf("value: %x read %d bytes\n", data, bytesread) // 用bytes.Equal严谨对比字节切片 if bytes.Equal(data, magic64) { fmt.Println("64 bit header found") } else if bytes.Equal(data, magic32) { fmt.Println("32 bit header found") } }
方法二:转换为整数后对比(考虑字节序)
使用Go标准库的encoding/binary包,把读取到的字节切片转换成uint64类型,注意要使用小端序(因为你的输出显示文件是小端存储),然后和魔法值的整数形式对比。
代码示例:
package main import ( "encoding/binary" "fmt" "log" "os" ) func main() { path := "test.exe.16900.sancov" f, err := os.Open(path) if err != nil { log.Fatal("Error while opening file", err) } defer f.Close() data := make([]byte, 8) bytesread, err := f.Read(data) if err != nil { log.Fatal("Error reading magic bytes:", err) } if bytesread != 8 { log.Fatal("Expected 8 bytes for magic header, got", bytesread) } fmt.Printf("value: %x read %d bytes\n", data, bytesread) // 小端序转换为uint64 magicValue := binary.LittleEndian.Uint64(data) const magic64 = 0xC0BFFFFFFFFFFF64 const magic32 = 0xC0BFFFFFFFFFFF32 if magicValue == magic64 { fmt.Println("64 bit header found") } else if magicValue == magic32 { fmt.Println("32 bit header found") } }
这个方法的好处是可以直接用文档里给出的魔法值常量,不需要手动转换字节顺序,binary.LittleEndian会帮你处理小端到大端的转换。
额外需要注意的点
- 你的原代码里用了
for循环不断读8字节,但SanCov的魔法值只在文件开头出现一次,读完魔法值后应该按格式读取后续的PC数据,不需要循环读。 - 一定要记得关闭文件(用
defer f.Close()),避免资源泄漏。 - 错误处理不能忽略,原代码里忽略了
Read的错误,实际开发中要处理这些错误,避免程序静默失败。
内容的提问来源于stack exchange,提问作者user961346
相关产品推荐
相关产品推荐

